Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2894797
celerity_mapper.php
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
11 KB
Referenced Files
None
Subscribers
None
celerity_mapper.php
View Options
#!/usr/bin/env php
<?php
$package_spec
=
array
(
'javelin.pkg.js'
=>
array
(
'javelin-util'
,
'javelin-install'
,
'javelin-event'
,
'javelin-stratcom'
,
'javelin-behavior'
,
'javelin-resource'
,
'javelin-request'
,
'javelin-vector'
,
'javelin-dom'
,
'javelin-json'
,
'javelin-uri'
,
'javelin-workflow'
,
'javelin-mask'
,
'javelin-typeahead'
,
'javelin-typeahead-normalizer'
,
'javelin-typeahead-source'
,
'javelin-typeahead-preloaded-source'
,
'javelin-typeahead-ondemand-source'
,
'javelin-tokenizer'
,
'javelin-fx'
,
'javelin-color'
,
)
,
'core.pkg.js'
=>
array
(
'javelin-behavior-aphront-basic-tokenizer'
,
'javelin-behavior-workflow'
,
'javelin-behavior-aphront-form-disable-on-submit'
,
'phabricator-keyboard-shortcut-manager'
,
'phabricator-keyboard-shortcut'
,
'javelin-behavior-phabricator-keyboard-shortcuts'
,
'javelin-behavior-refresh-csrf'
,
'javelin-behavior-phabricator-watch-anchor'
,
'javelin-behavior-phabricator-autofocus'
,
'phabricator-paste-file-upload'
,
'phabricator-menu-item'
,
'phabricator-dropdown-menu'
,
'javelin-behavior-phabricator-oncopy'
,
'phabricator-tooltip'
,
'javelin-behavior-phabricator-tooltips'
,
'phabricator-prefab'
,
'javelin-behavior-device'
,
'javelin-behavior-toggle-class'
,
'javelin-behavior-lightbox-attachments'
,
'phabricator-busy'
,
'javelin-aphlict'
,
'phabricator-notification'
,
'javelin-behavior-aphlict-listen'
,
'javelin-behavior-phabricator-search-typeahead'
,
'javelin-behavior-konami'
,
'javelin-behavior-aphlict-dropdown'
,
'javelin-behavior-phabricator-active-nav'
,
'javelin-behavior-phabricator-nav'
,
'javelin-behavior-phabricator-remarkup-assist'
,
'phabricator-textareautils'
,
'phabricator-file-upload'
,
)
,
'core.pkg.css'
=>
array
(
'phabricator-core-css'
,
'phabricator-core-buttons-css'
,
'phabricator-standard-page-view'
,
'aphront-dialog-view-css'
,
'aphront-form-view-css'
,
'aphront-panel-view-css'
,
'aphront-side-nav-view-css'
,
'aphront-table-view-css'
,
'aphront-crumbs-view-css'
,
'aphront-tokenizer-control-css'
,
'aphront-typeahead-control-css'
,
'aphront-list-filter-view-css'
,
'phabricator-directory-css'
,
'phabricator-jump-nav'
,
'phabricator-app-buttons-css'
,
'phabricator-remarkup-css'
,
'syntax-highlighting-css'
,
'aphront-pager-view-css'
,
'phabricator-transaction-view-css'
,
'aphront-tooltip-css'
,
'aphront-headsup-view-css'
,
'phabricator-flag-css'
,
'aphront-error-view-css'
,
'autosprite-css'
,
'sprite-icon-css'
,
'phabricator-main-menu-view'
,
'phabricator-notification-css'
,
'phabricator-notification-menu-css'
,
'lightbox-attachment-css'
,
'phabricator-header-view-css'
,
'phabricator-form-view-css'
,
'phabricator-filetree-view-css'
,
'phabricator-nav-view-css'
,
)
,
'differential.pkg.css'
=>
array
(
'differential-core-view-css'
,
'differential-changeset-view-css'
,
'differential-results-table-css'
,
'differential-revision-history-css'
,
'differential-revision-list-css'
,
'differential-table-of-contents-css'
,
'differential-revision-comment-css'
,
'differential-revision-add-comment-css'
,
'differential-revision-comment-list-css'
,
'phabricator-object-selector-css'
,
'aphront-headsup-action-list-view-css'
,
'phabricator-content-source-view-css'
,
'differential-local-commits-view-css'
,
'inline-comment-summary-css'
,
)
,
'differential.pkg.js'
=>
array
(
'phabricator-drag-and-drop-file-upload'
,
'phabricator-shaped-request'
,
'javelin-behavior-differential-feedback-preview'
,
'javelin-behavior-differential-edit-inline-comments'
,
'javelin-behavior-differential-populate'
,
'javelin-behavior-differential-show-more'
,
'javelin-behavior-differential-diff-radios'
,
'javelin-behavior-differential-accept-with-errors'
,
'javelin-behavior-differential-comment-jump'
,
'javelin-behavior-differential-add-reviewers-and-ccs'
,
'javelin-behavior-differential-keyboard-navigation'
,
'javelin-behavior-aphront-drag-and-drop'
,
'javelin-behavior-aphront-drag-and-drop-textarea'
,
'javelin-behavior-phabricator-object-selector'
,
'javelin-behavior-repository-crossreference'
,
'differential-inline-comment-editor'
,
'javelin-behavior-differential-dropdown-menus'
,
'javelin-behavior-differential-toggle-files'
,
'javelin-behavior-differential-user-select'
,
)
,
'diffusion.pkg.css'
=>
array
(
'diffusion-commit-view-css'
,
'diffusion-icons-css'
,
)
,
'diffusion.pkg.js'
=>
array
(
'javelin-behavior-diffusion-pull-lastmodified'
,
'javelin-behavior-diffusion-commit-graph'
,
'javelin-behavior-audit-preview'
,
)
,
'maniphest.pkg.css'
=>
array
(
'maniphest-task-summary-css'
,
'maniphest-transaction-detail-css'
,
'aphront-attached-file-view-css'
,
'phabricator-project-tag-css'
,
)
,
'maniphest.pkg.js'
=>
array
(
'javelin-behavior-maniphest-batch-selector'
,
'javelin-behavior-maniphest-transaction-controls'
,
'javelin-behavior-maniphest-transaction-preview'
,
'javelin-behavior-maniphest-transaction-expand'
,
'javelin-behavior-maniphest-subpriority-editor'
,
)
,
'darkconsole.pkg.js'
=>
array
(
'javelin-behavior-dark-console-ajax'
,
'javelin-behavior-dark-console'
,
'javelin-behavior-error-log'
,
)
,
)
;
require_once
dirname
(
__FILE__
)
.
'/__init_script__.php'
;
$args
=
new
PhutilArgumentParser
(
$argv
)
;
$args
->
setTagline
(
'map static resources'
)
;
$args
->
setSynopsis
(
"**celerity_mapper.php** [--output __path__] [--with-custom] <webroot>"
)
;
$args
->
parse
(
array
(
array
(
'name'
=>
'output'
,
'param'
=>
'path'
,
'default'
=>
'../src/__celerity_resource_map__.php'
,
'help'
=>
"Set the path for resource map. It is usually useful for "
.
"'celerity.resource-path' configuration."
,
)
,
array
(
'name'
=>
'with-custom'
,
'help'
=>
'Include resources in <webroot>/rsrc/custom/.'
,
)
,
array
(
'name'
=>
'webroot'
,
'wildcard'
=>
true
,
)
,
)
)
;
$root
=
$args
->
getArg
(
'webroot'
)
;
if
(
count
(
$root
)
!=
1
||
!
is_dir
(
reset
(
$root
)
)
)
{
$args
->
printHelpAndExit
(
)
;
}
$root
=
Filesystem
::
resolvePath
(
reset
(
$root
)
)
;
$celerity_path
=
Filesystem
::
resolvePath
(
$args
->
getArg
(
'output'
)
,
$root
)
;
$with_custom
=
$args
->
getArg
(
'with-custom'
)
;
$resource_hash
=
PhabricatorEnv
::
getEnvConfig
(
'celerity.resource-hash'
)
;
$runtime_map
=
array
(
)
;
echo
"Finding raw static resources...\n"
;
$finder
=
id
(
new
FileFinder
(
$root
)
)
->
withType
(
'f'
)
->
withSuffix
(
'png'
)
->
withSuffix
(
'jpg'
)
->
withSuffix
(
'gif'
)
->
withSuffix
(
'swf'
)
->
withFollowSymlinks
(
true
)
->
setGenerateChecksums
(
true
)
;
if
(
!
$with_custom
)
{
$finder
->
excludePath
(
'./rsrc/custom'
)
;
}
$raw_files
=
$finder
->
find
(
)
;
echo
"Processing "
.
count
(
$raw_files
)
.
" files"
;
foreach
(
$raw_files
as
$path
=>
$hash
)
{
echo
"."
;
$path
=
'/'
.
Filesystem
::
readablePath
(
$path
,
$root
)
;
$type
=
CelerityResourceTransformer
::
getResourceType
(
$path
)
;
$hash
=
md5
(
$hash
.
$path
.
$resource_hash
)
;
$uri
=
'/res/'
.
substr
(
$hash
,
0
,
8
)
.
$path
;
$runtime_map
[
$path
]
=
array
(
'hash'
=>
$hash
,
'uri'
=>
$uri
,
'disk'
=>
$path
,
'type'
=>
$type
,
)
;
}
echo
"\n"
;
$xformer
=
id
(
new
CelerityResourceTransformer
(
)
)
->
setMinify
(
false
)
->
setRawResourceMap
(
$runtime_map
)
;
echo
"Finding transformable static resources...\n"
;
$finder
=
id
(
new
FileFinder
(
$root
)
)
->
withType
(
'f'
)
->
withSuffix
(
'js'
)
->
withSuffix
(
'css'
)
->
withFollowSymlinks
(
true
)
->
setGenerateChecksums
(
true
)
;
if
(
!
$with_custom
)
{
$finder
->
excludePath
(
'./rsrc/custom'
)
;
}
$files
=
$finder
->
find
(
)
;
echo
"Processing "
.
count
(
$files
)
.
" files"
;
$file_map
=
array
(
)
;
foreach
(
$files
as
$path
=>
$raw_hash
)
{
echo
"."
;
$path
=
'/'
.
Filesystem
::
readablePath
(
$path
,
$root
)
;
$data
=
Filesystem
::
readFile
(
$root
.
$path
)
;
$data
=
$xformer
->
transformResource
(
$path
,
$data
)
;
$hash
=
md5
(
$data
)
;
$hash
=
md5
(
$hash
.
$path
.
$resource_hash
)
;
$file_map
[
$path
]
=
array
(
'hash'
=>
$hash
,
'disk'
=>
$path
,
)
;
}
echo
"\n"
;
$resource_graph
=
array
(
)
;
$hash_map
=
array
(
)
;
$parser
=
new
PhutilDocblockParser
(
)
;
foreach
(
$file_map
as
$path
=>
$info
)
{
$type
=
CelerityResourceTransformer
::
getResourceType
(
$path
)
;
$data
=
Filesystem
::
readFile
(
$root
.
$info
[
'disk'
]
)
;
$matches
=
array
(
)
;
$ok
=
preg_match
(
'@/[*][*].*?[*]/@s'
,
$data
,
$matches
)
;
if
(
!
$ok
)
{
throw
new
Exception
(
"File {$path} does not have a header doc comment. Encode dependency "
.
"data in a header docblock."
)
;
}
list
(
$description
,
$metadata
)
=
$parser
->
parse
(
$matches
[
0
]
)
;
$provides
=
preg_split
(
'/\s+/'
,
trim
(
idx
(
$metadata
,
'provides'
)
)
)
;
$requires
=
preg_split
(
'/\s+/'
,
trim
(
idx
(
$metadata
,
'requires'
)
)
)
;
$provides
=
array_filter
(
$provides
)
;
$requires
=
array_filter
(
$requires
)
;
if
(
!
$provides
)
{
// Tests and documentation-only JS is permitted to @provide no targets.
continue
;
}
if
(
count
(
$provides
)
>
1
)
{
throw
new
Exception
(
"File {$path} must @provide at most one Celerity target."
)
;
}
$provides
=
reset
(
$provides
)
;
$uri
=
'/res/'
.
substr
(
$info
[
'hash'
]
,
0
,
8
)
.
$path
;
$hash_map
[
$provides
]
=
$info
[
'hash'
]
;
$resource_graph
[
$provides
]
=
$requires
;
$runtime_map
[
$provides
]
=
array
(
'uri'
=>
$uri
,
'type'
=>
$type
,
'requires'
=>
$requires
,
'disk'
=>
$path
,
)
;
}
$celerity_resource_graph
=
new
CelerityResourceGraph
(
)
;
$celerity_resource_graph
->
addNodes
(
$resource_graph
)
;
$celerity_resource_graph
->
setResourceGraph
(
$resource_graph
)
;
$celerity_resource_graph
->
loadGraph
(
)
;
foreach
(
$resource_graph
as
$provides
=>
$requires
)
{
$cycle
=
$celerity_resource_graph
->
detectCycles
(
$provides
)
;
if
(
$cycle
)
{
throw
new
Exception
(
"Cycle detected in resource graph: "
.
implode
(
$cycle
,
" => "
)
)
;
}
}
$package_map
=
array
(
)
;
foreach
(
$package_spec
as
$name
=>
$package
)
{
$hashes
=
array
(
)
;
$type
=
null
;
foreach
(
$package
as
$symbol
)
{
if
(
empty
(
$hash_map
[
$symbol
]
)
)
{
throw
new
Exception
(
"Package specification for '{$name}' includes '{$symbol}', but that "
.
"symbol is not defined anywhere."
)
;
}
if
(
$type
===
null
)
{
$type
=
$runtime_map
[
$symbol
]
[
'type'
]
;
}
else
{
$ntype
=
$runtime_map
[
$symbol
]
[
'type'
]
;
if
(
$type
!==
$ntype
)
{
throw
new
Exception
(
"Package specification for '{$name}' mixes resources of type "
.
"'{$type}' with resources of type '{$ntype}'. Each package may only "
.
"contain one type of resource."
)
;
}
}
$hashes
[
]
=
$symbol
.
':'
.
$hash_map
[
$symbol
]
;
}
$key
=
substr
(
md5
(
implode
(
"\n"
,
$hashes
)
)
,
0
,
8
)
;
$package_map
[
'packages'
]
[
$key
]
=
array
(
'name'
=>
$name
,
'symbols'
=>
$package
,
'uri'
=>
'/res/pkg/'
.
$key
.
'/'
.
$name
,
'type'
=>
$type
,
)
;
foreach
(
$package
as
$symbol
)
{
$package_map
[
'reverse'
]
[
$symbol
]
=
$key
;
}
}
ksort
(
$runtime_map
)
;
$runtime_map
=
var_export
(
$runtime_map
,
true
)
;
$runtime_map
=
preg_replace
(
'/\s+$/m'
,
''
,
$runtime_map
)
;
$runtime_map
=
preg_replace
(
'/array \(/'
,
'array('
,
$runtime_map
)
;
$package_map
[
'packages'
]
=
isort
(
$package_map
[
'packages'
]
,
'name'
)
;
ksort
(
$package_map
[
'reverse'
]
)
;
$package_map
=
var_export
(
$package_map
,
true
)
;
$package_map
=
preg_replace
(
'/\s+$/m'
,
''
,
$package_map
)
;
$package_map
=
preg_replace
(
'/array \(/'
,
'array('
,
$package_map
)
;
$generated
=
'@'
.
'generated'
;
$resource_map
=
<<<EOFILE
<?php
/**
* This file is automatically generated. Use 'celerity_mapper.php' to rebuild
* it.
* {$generated}
*/
celerity_register_resource_map({$runtime_map}, {$package_map});
EOFILE
;
echo
"Writing map...\n"
;
Filesystem
::
writeFile
(
$celerity_path
,
$resource_map
)
;
echo
"Done.\n"
;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 19, 20:30 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128453
Default Alt Text
celerity_mapper.php (11 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment