Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F96174739
PhragmentGetPatchConduitAPIMethod.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
Mon, Dec 23, 11:19
Size
6 KB
Mime Type
text/x-php
Expires
Wed, Dec 25, 11:19 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
23130648
Attached To
rPH Phabricator
PhragmentGetPatchConduitAPIMethod.php
View Options
<?php
final
class
PhragmentGetPatchConduitAPIMethod
extends
PhragmentConduitAPIMethod
{
public
function
getAPIMethodName
()
{
return
'phragment.getpatch'
;
}
public
function
getMethodStatus
()
{
return
self
::
METHOD_STATUS_UNSTABLE
;
}
public
function
getMethodDescription
()
{
return
pht
(
'Retrieve the patches to apply for a given set of files.'
);
}
public
function
defineParamTypes
()
{
return
array
(
'path'
=>
'required string'
,
'state'
=>
'required dict<string, string>'
,
);
}
public
function
defineReturnType
()
{
return
'nonempty dict'
;
}
public
function
defineErrorTypes
()
{
return
array
(
'ERR_BAD_FRAGMENT'
=>
'No such fragment exists'
,
);
}
protected
function
execute
(
ConduitAPIRequest
$request
)
{
$path
=
$request
->
getValue
(
'path'
);
$state
=
$request
->
getValue
(
'state'
);
// The state is an array mapping file paths to hashes.
$patches
=
array
();
// We need to get all of the mappings (like phragment.getstate) first
// so that we can detect deletions and creations of files.
$fragment
=
id
(
new
PhragmentFragmentQuery
())
->
setViewer
(
$request
->
getUser
())
->
withPaths
(
array
(
$path
))
->
executeOne
();
if
(
$fragment
===
null
)
{
throw
new
ConduitException
(
'ERR_BAD_FRAGMENT'
);
}
$mappings
=
$fragment
->
getFragmentMappings
(
$request
->
getUser
(),
$fragment
->
getPath
());
$file_phids
=
mpull
(
mpull
(
$mappings
,
'getLatestVersion'
),
'getFilePHID'
);
$files
=
id
(
new
PhabricatorFileQuery
())
->
setViewer
(
$request
->
getUser
())
->
withPHIDs
(
$file_phids
)
->
execute
();
$files
=
mpull
(
$files
,
null
,
'getPHID'
);
// Scan all of the files that the caller currently has and iterate
// over that.
foreach
(
$state
as
$path
=>
$hash
)
{
// If $mappings[$path] exists, then the user has the file and it's
// also a fragment.
if
(
array_key_exists
(
$path
,
$mappings
))
{
$file_phid
=
$mappings
[
$path
]->
getLatestVersion
()->
getFilePHID
();
if
(
$file_phid
!==
null
)
{
// If the file PHID is present, then we need to check the
// hashes to see if they are the same.
$hash_caller
=
strtolower
(
$state
[
$path
]);
$hash_current
=
$files
[
$file_phid
]->
getContentHash
();
if
(
$hash_caller
===
$hash_current
)
{
// The user's version is identical to our version, so
// there is no update needed.
}
else
{
// The hash differs, and the user needs to update.
$patches
[]
=
array
(
'path'
=>
$path
,
'fileOld'
=>
null
,
'fileNew'
=>
$files
[
$file_phid
],
'hashOld'
=>
$hash_caller
,
'hashNew'
=>
$hash_current
,
'patchURI'
=>
null
);
}
}
else
{
// We have a record of this as a file, but there is no file
// attached to the latest version, so we consider this to be
// a deletion.
$patches
[]
=
array
(
'path'
=>
$path
,
'fileOld'
=>
null
,
'fileNew'
=>
null
,
'hashOld'
=>
$hash_caller
,
'hashNew'
=>
PhragmentPatchUtil
::
EMPTY_HASH
,
'patchURI'
=>
null
);
}
}
else
{
// If $mappings[$path] does not exist, then the user has a file,
// and we have absolutely no record of it what-so-ever (we haven't
// even recorded a deletion). Assuming most applications will store
// some form of data near their own files, this is probably a data
// file relevant for the application that is not versioned, so we
// don't tell the client to do anything with it.
}
}
// Check the remaining files that we know about but the caller has
// not reported.
foreach
(
$mappings
as
$path
=>
$child
)
{
if
(
array_key_exists
(
$path
,
$state
))
{
// We have already evaluated this above.
}
else
{
$file_phid
=
$mappings
[
$path
]->
getLatestVersion
()->
getFilePHID
();
if
(
$file_phid
!==
null
)
{
// If the file PHID is present, then this is a new file that
// we know about, but the caller does not. We need to tell
// the caller to create the file.
$hash_current
=
$files
[
$file_phid
]->
getContentHash
();
$patches
[]
=
array
(
'path'
=>
$path
,
'fileOld'
=>
null
,
'fileNew'
=>
$files
[
$file_phid
],
'hashOld'
=>
PhragmentPatchUtil
::
EMPTY_HASH
,
'hashNew'
=>
$hash_current
,
'patchURI'
=>
null
);
}
else
{
// We have a record of deleting this file, and the caller hasn't
// reported it, so they've probably deleted it in a previous
// update.
}
}
}
// Before we can calculate patches, we need to resolve the old versions
// of files so we can draw diffs on them.
$hashes
=
array
();
foreach
(
$patches
as
$patch
)
{
if
(
$patch
[
'hashOld'
]
!==
PhragmentPatchUtil
::
EMPTY_HASH
)
{
$hashes
[]
=
$patch
[
'hashOld'
];
}
}
$old_files
=
array
();
if
(
count
(
$hashes
)
!==
0
)
{
$old_files
=
id
(
new
PhabricatorFileQuery
())
->
setViewer
(
$request
->
getUser
())
->
withContentHashes
(
$hashes
)
->
execute
();
}
$old_files
=
mpull
(
$old_files
,
null
,
'getContentHash'
);
foreach
(
$patches
as
$key
=>
$patch
)
{
if
(
$patch
[
'hashOld'
]
!==
PhragmentPatchUtil
::
EMPTY_HASH
)
{
if
(
array_key_exists
(
$patch
[
'hashOld'
],
$old_files
))
{
$patches
[
$key
][
'fileOld'
]
=
$old_files
[
$patch
[
'hashOld'
]];
}
else
{
// We either can't see or can't read the old file.
$patches
[
$key
][
'hashOld'
]
=
PhragmentPatchUtil
::
EMPTY_HASH
;
$patches
[
$key
][
'fileOld'
]
=
null
;
}
}
}
// Now run through all of the patch entries, calculate the patches
// and return the results.
foreach
(
$patches
as
$key
=>
$patch
)
{
$data
=
PhragmentPatchUtil
::
calculatePatch
(
$patches
[
$key
][
'fileOld'
],
$patches
[
$key
][
'fileNew'
]);
unset
(
$patches
[
$key
][
'fileOld'
]);
unset
(
$patches
[
$key
][
'fileNew'
]);
$file
=
PhabricatorFile
::
buildFromFileDataOrHash
(
$data
,
array
(
'name'
=>
'patch.dmp'
,
'ttl'
=>
time
()
+
60
*
60
*
24
,
));
$patches
[
$key
][
'patchURI'
]
=
$file
->
getDownloadURI
();
}
return
$patches
;
}
}
Event Timeline
Log In to Comment