diff -Nru phabricator-0~git20200925/arcanist/resources/ssl/default.pem phabricator-0~git20220903/arcanist/resources/ssl/default.pem --- phabricator-0~git20200925/arcanist/resources/ssl/default.pem 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/resources/ssl/default.pem 2022-05-17 23:15:03.000000000 +0000 @@ -1,20 +1,20 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Wed Jan 20 04:12:04 2016 +## Certificate data from Mozilla as of: Tue Oct 26 03:12:05 2021 GMT ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: -## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## -## Conversion done with mk-ca-bundle.pl version 1.25. -## SHA1: 0ab47e2f41518f8d223eab517cb799e5b071231e +## Conversion done with mk-ca-bundle.pl version 1.28. +## SHA256: bb36818a81feaa4cca61101e6d6276cd09e972efcb08112dfed846918ca41d7f ## @@ -61,30 +61,6 @@ TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- -Verisign Class 3 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 -EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc -cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw -EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj -055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA -ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f -j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC -/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 -xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa -t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== ------END CERTIFICATE----- - Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- @@ -130,102 +106,6 @@ RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -AddTrust Low-Value Services Root -================================ ------BEGIN CERTIFICATE----- -MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU -cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw -CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO -ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 -54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr -oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 -Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui -GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w -HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT -RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw -HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt -ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph -iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY -eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr -mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj -ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= ------END CERTIFICATE----- - -AddTrust External Root -====================== ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD -VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw -NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU -cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg -Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 -+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw -Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo -aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy -2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 -7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL -VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk -VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB -IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl -j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 -e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u -G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= ------END CERTIFICATE----- - -AddTrust Public Services Root -============================= ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU -cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ -BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l -dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu -nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i -d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG -Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw -HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G -A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G -A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 -JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL -+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao -GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 -Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H -EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= ------END CERTIFICATE----- - -AddTrust Qualified Certificates Root -==================================== ------BEGIN CERTIFICATE----- -MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU -cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx -CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ -IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx -64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 -KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o -L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR -wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU -MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE -BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y -azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG -GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X -dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze -RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB -iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= ------END CERTIFICATE----- - Entrust Root Certification Authority ==================================== -----BEGIN CERTIFICATE----- @@ -252,170 +132,6 @@ tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -RSA Security 2048 v3 -==================== ------BEGIN CERTIFICATE----- -MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK -ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy -MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb -BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 -Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb -WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH -KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP -+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ -MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E -FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY -v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj -0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj -VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 -nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA -pKnXwiJPZ9d37CAFYd4= ------END CERTIFICATE----- - -GeoTrust Global CA -================== ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK -Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw -MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j -LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo -BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet -8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc -T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU -vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk -DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q -zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 -d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 -mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p -XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm -Mw== ------END CERTIFICATE----- - -GeoTrust Global CA 2 -==================== ------BEGIN CERTIFICATE----- -MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw -MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j -LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ -NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k -LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA -Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b -HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH -K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 -srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh -ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL -OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC -x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF -H4z1Ir+rzoPz4iIprn2DQKi6bA== ------END CERTIFICATE----- - -GeoTrust Universal CA -===================== ------BEGIN CERTIFICATE----- -MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 -MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu -Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t -JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e -RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs -7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d -8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V -qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga -Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB -Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu -KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 -ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 -XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB -hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc -aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 -qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL -oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK -xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF -KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 -DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK -xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU -p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI -P/rmMuGNG2+k5o7Y+SlIis5z/iw= ------END CERTIFICATE----- - -GeoTrust Universal CA 2 -======================= ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 -MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg -SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 -DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 -j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q -JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a -QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 -WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP -20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn -ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC -SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG -8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 -+/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E -BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z -dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ -4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ -mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq -A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg -Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP -pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d -FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp -gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm -X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS ------END CERTIFICATE----- - -Visa eCommerce Root -=================== ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG -EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug -QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 -WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm -VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv -bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL -F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b -RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 -TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI -/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs -GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG -MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc -CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW -YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz -zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu -YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt -398znM/jra6O1I7mT1GvFpLgXPYHDw== ------END CERTIFICATE----- - -Certum Root CA -============== ------BEGIN CERTIFICATE----- -MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK -ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla -Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u -by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x -wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL -kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ -89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K -Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P -NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ -GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg -GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ -0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS -qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== ------END CERTIFICATE----- - Comodo AAA Services root ======================== -----BEGIN CERTIFICATE----- @@ -440,88 +156,6 @@ 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -Comodo Secure Services root -=========================== ------BEGIN CERTIFICATE----- -MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg -TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw -MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu -Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi -BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP -9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc -rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC -oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V -p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E -FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w -gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj -YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm -aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm -4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj -Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL -DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw -pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H -RR3B7Hzs/Sk= ------END CERTIFICATE----- - -Comodo Trusted Services root -============================ ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg -TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw -MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h -bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw -IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 -3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y -/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 -juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS -ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud -DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp -ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl -cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw -uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 -pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA -BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l -R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O -9y5Xt5hwXsjEeLBi ------END CERTIFICATE----- - -QuoVadis Root CA -================ ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE -ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz -MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp -cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD -EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk -J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL -F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL -YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen -AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w -PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y -ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 -MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj -YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs -ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW -Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu -BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw -FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 -tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo -fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul -LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x -gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi -5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi -5nrQNiOKSnQ2+Q== ------END CERTIFICATE----- - QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- @@ -609,163 +243,6 @@ FL39vmwLAw== -----END CERTIFICATE----- -Sonera Class 2 Root CA -====================== ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG -U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw -NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh -IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 -/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT -dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG -f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P -tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH -nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT -XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt -0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI -cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph -Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx -EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH -llpwrN9M ------END CERTIFICATE----- - -Staat der Nederlanden Root CA -============================= ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE -ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g -Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w -HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh -bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt -vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P -jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca -C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth -vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 -22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV -HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v -dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN -BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR -EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw -MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y -nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR -iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== ------END CERTIFICATE----- - -UTN USERFirst Hardware Root CA -============================== ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd -BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx -OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 -eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz -ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI -wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd -tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 -i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf -Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw -gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF -lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF -UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF -BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM -//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW -XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 -lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn -iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 -nfhmqA== ------END CERTIFICATE----- - -Camerfirma Chambers of Commerce Root -==================================== ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe -QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i -ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx -NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp -cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn -MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC -AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU -xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH -NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW -DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV -d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud -EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v -cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P -AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh -bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD -VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz -aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi -fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD -L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN -UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n -ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 -erfutGWaIZDgqtCYvDi1czyL+Nw= ------END CERTIFICATE----- - -Camerfirma Global Chambersign Root -================================== ------BEGIN CERTIFICATE----- -MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe -QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i -ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx -NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt -YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg -MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw -ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J -1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O -by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl -6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c -8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ -BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j -aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B -Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj -aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y -ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh -bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA -PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y -gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ -PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 -IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes -t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== ------END CERTIFICATE----- - -NetLock Notary (Class A) Root -============================= ------BEGIN CERTIFICATE----- -MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI -EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 -dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j -ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX -DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH -EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD -VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz -cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM -D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ -z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC -/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 -tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 -4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG -A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC -Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv -bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu -IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn -LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 -ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz -IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh -IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu -b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh -bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg -Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp -bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 -ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP -ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB -CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr -KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM -8CgHrTwXZoi1/baI ------END CERTIFICATE----- - XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- @@ -838,109 +315,6 @@ QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- -StartCom Certification Authority -================================ ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN -U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu -ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 -NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk -LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg -U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y -o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ -Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d -eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt -2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z -6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ -osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ -untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc -UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT -37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj -YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH -AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw -Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg -U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 -LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl -cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh -cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT -dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC -AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh -3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm -vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk -fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 -fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ -EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl -1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ -lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro -g14= ------END CERTIFICATE----- - -Taiwan GRCA -=========== ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG -EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X -DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv -dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN -w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 -BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O -1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO -htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov -J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 -Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t -B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB -O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 -lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV -HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 -09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ -TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj -Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 -Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU -D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz -DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk -Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk -7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ -CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy -+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS ------END CERTIFICATE----- - -Swisscom Root CA 1 -================== ------BEGIN CERTIFICATE----- -MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG -EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy -dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 -MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln -aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC -IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM -MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF -NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe -AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC -b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn -7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN -cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp -WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 -haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY -MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw -HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j -BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 -MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn -jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ -MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H -VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl -vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl -OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 -1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq -nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy -x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW -NY6E0F/6MBr1mmz0DlP5OlvRHA== ------END CERTIFICATE----- - DigiCert Assured ID Root CA =========================== -----BEGIN CERTIFICATE----- @@ -1007,72 +381,6 @@ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- -Certplus Class 2 Primary CA -=========================== ------BEGIN CERTIFICATE----- -MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE -BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN -OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy -dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR -5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ -Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO -YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e -e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME -CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ -YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t -L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD -P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R -TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ -7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW -//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 -l7+ijrRU ------END CERTIFICATE----- - -DST Root CA X3 -============== ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK -ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X -DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 -cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT -rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 -UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy -xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d -utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ -MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug -dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE -GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw -RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS -fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- - -DST ACES CA X6 -============== ------BEGIN CERTIFICATE----- -MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG -EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT -MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha -MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE -CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI -DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa -pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow -GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy -MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu -Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy -dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU -CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 -5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t -Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq -nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs -vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 -oKfN5XozNmr6mis= ------END CERTIFICATE----- - SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- @@ -1135,78 +443,6 @@ DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- -GeoTrust Primary Certification Authority -======================================== ------BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx -CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ -cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN -b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 -nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge -RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt -tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI -hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K -Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN -NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa -Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG -1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= ------END CERTIFICATE----- - -thawte Primary Root CA -====================== ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE -BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 -aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 -MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg -SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv -KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT -FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs -oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ -1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc -q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K -aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p -afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF -AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE -uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX -xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 -jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH -z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== ------END CERTIFICATE----- - -VeriSign Class 3 Public Primary Certification Authority - G5 -============================================================ ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO -ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk -IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln -biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh -dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz -j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD -Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ -Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r -fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv -Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG -SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ -X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE -KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC -Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE -ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- - SecureTrust CA ============== -----BEGIN CERTIFICATE----- @@ -1298,33 +534,6 @@ ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- -WellsSecure Public Root Certificate Authority -============================================= ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM -F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw -NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN -MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl -bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD -VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 -iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 -i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 -bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB -K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB -AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu -cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm -lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB -i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww -GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg -Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI -K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 -bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj -qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es -E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ -tylv2G0xffX8oRAHh84vWdw+WNs= ------END CERTIFICATE----- - COMODO ECC Certification Authority ================================== -----BEGIN CERTIFICATE----- @@ -1342,114 +551,6 @@ U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- -IGC/A -===== ------BEGIN CERTIFICATE----- -MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD -VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE -Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy -MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI -EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT -STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 -TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW -So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy -HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd -frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ -tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB -egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC -iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK -q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q -MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg -Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI -lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF -0mBWWg== ------END CERTIFICATE----- - -Security Communication EV RootCA1 -================================= ------BEGIN CERTIFICATE----- -MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc -U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh -dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE -BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl -Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO -/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX -WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z -ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 -bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK -9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG -SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm -iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG -Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW -mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW -T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 ------END CERTIFICATE----- - -OISTE WISeKey Global Root GA CA -=============================== ------BEGIN CERTIFICATE----- -MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE -BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG -A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH -bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD -VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw -IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 -IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 -Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg -Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD -d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ -/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R -LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ -KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm -MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 -+vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa -hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY -okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= ------END CERTIFICATE----- - -Microsec e-Szigno Root CA -========================= ------BEGIN CERTIFICATE----- -MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE -BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL -EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 -MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz -dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT -GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG -d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N -oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc -QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ -PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb -MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG -IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD -VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 -LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A -dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn -AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA -4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg -AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA -egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 -Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO -PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv -c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h -cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw -IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT -WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV -MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER -MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp -Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal -HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT -nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE -aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a -86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK -yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB -S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= ------END CERTIFICATE----- - Certigna ======== -----BEGIN CERTIFICATE----- @@ -1472,28 +573,6 @@ WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- -Deutsche Telekom Root CA 2 -========================== ------BEGIN CERTIFICATE----- -MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT -RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG -A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 -MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G -A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS -b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 -bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI -KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY -AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK -Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV -jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV -HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr -E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy -zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 -rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G -dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU -Cm26OWMohpLzGITY+9HPBVZkVw== ------END CERTIFICATE----- - Cybertrust Global Root ====================== -----BEGIN CERTIFICATE----- @@ -1547,86 +626,6 @@ BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- -T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 -============================================================================================================================= ------BEGIN CERTIFICATE----- -MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH -DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q -aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry -b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV -BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg -S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 -MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl -IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF -n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl -IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft -dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl -cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO -Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 -xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR -6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL -hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd -BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 -N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT -y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh -LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M -dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= ------END CERTIFICATE----- - -Buypass Class 2 CA 1 -==================== ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 -MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh -c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M -cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 -0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 -0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R -uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P -AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV -1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt -7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 -fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w -wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho ------END CERTIFICATE----- - -EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 -========================================================================== ------BEGIN CERTIFICATE----- -MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg -QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe -Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p -ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt -IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by -X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b -gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr -eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ -TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy -Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn -uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI -qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm -ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 -Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW -Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t -FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm -zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k -XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT -bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU -RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK -1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt -2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ -Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 -AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT ------END CERTIFICATE----- - certSIGN ROOT CA ================ -----BEGIN CERTIFICATE----- @@ -1647,181 +646,8 @@ TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD -----END CERTIFICATE----- -CNNIC ROOT -========== ------BEGIN CERTIFICATE----- -MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE -ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw -OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD -o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz -VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT -VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or -czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK -y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC -wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S -lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 -Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM -O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 -BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 -G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m -mxE= ------END CERTIFICATE----- - -ApplicationCA - Japanese Government -=================================== ------BEGIN CERTIFICATE----- -MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT -SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw -MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl -cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 -fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN -wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE -jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu -nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU -WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV -BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD -vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs -o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g -/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD -io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW -dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL -rosot4LKGAfmt1t06SAZf7IbiVQ= ------END CERTIFICATE----- - -GeoTrust Primary Certification Authority - G3 -============================================= ------BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE -BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 -IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz -NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo -YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT -LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j -K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE -c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C -IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu -dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr -2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 -cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE -Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD -AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s -t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt ------END CERTIFICATE----- - -thawte Primary Root CA - G2 -=========================== ------BEGIN CERTIFICATE----- -MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC -VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu -IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg -Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV -MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG -b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt -IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS -LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 -8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU -mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN -G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K -rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== ------END CERTIFICATE----- - -thawte Primary Root CA - G3 -=========================== ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE -BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 -aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w -ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh -d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD -VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG -A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At -P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC -+BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY -7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW -vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ -KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK -A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu -t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC -8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm -er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= ------END CERTIFICATE----- - -GeoTrust Primary Certification Authority - G2 -============================================= ------BEGIN CERTIFICATE----- -MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu -Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 -OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg -MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl -b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG -BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc -KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ -EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m -ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 -npaqBA+K ------END CERTIFICATE----- - -VeriSign Universal Root Certification Authority -=============================================== ------BEGIN CERTIFICATE----- -MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO -ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk -IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj -1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP -MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 -9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I -AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR -tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G -CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O -a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud -DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 -Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx -Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx -P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P -wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 -mJO37M2CYfE45k+XmCpajQ== ------END CERTIFICATE----- - -VeriSign Class 3 Public Primary Certification Authority - G4 -============================================================ ------BEGIN CERTIFICATE----- -MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC -VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 -b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz -ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU -cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo -b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 -Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz -rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw -HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u -Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD -A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx -AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== ------END CERTIFICATE----- - NetLock Arany (Class Gold) FÅ‘tanúsítvány -============================================ +======================================== -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 @@ -1844,90 +670,6 @@ dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- -Staat der Nederlanden Root CA - G2 -================================== ------BEGIN CERTIFICATE----- -MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE -CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g -Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC -TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l -ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ -5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn -vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj -CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil -e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR -OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI -CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 -48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi -trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 -qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB -AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC -ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA -A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz -+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj -f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN -kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk -CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF -URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb -CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h -oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV -IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm -66+KAQ== ------END CERTIFICATE----- - -CA Disig -======== ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK -QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw -MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz -bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm -GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD -Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo -hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt -ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w -gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P -AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz -aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff -ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa -BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t -WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 -mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ -CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K -ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA -4Z7CRneC9VkGjCFMhwnN5ag= ------END CERTIFICATE----- - -Juur-SK -======= ------BEGIN CERTIFICATE----- -MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA -c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw -DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG -SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy -aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf -TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC -+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw -UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa -Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF -MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD -HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh -AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA -cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr -AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw -cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE -FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G -A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo -ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL -abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 -IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh -Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 -yyqcjg== ------END CERTIFICATE----- - Hongkong Post Root CA 1 ======================= -----BEGIN CERTIFICATE----- @@ -1969,37 +711,6 @@ lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- -ACEDICOM Root -============= ------BEGIN CERTIFICATE----- -MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD -T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 -MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG -A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk -WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD -YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew -MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb -m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk -HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT -xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 -3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 -2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq -TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz -4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU -9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv -bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg -aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP -eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk -zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 -ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI -KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq -nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE -I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp -MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o -tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== ------END CERTIFICATE----- - Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- @@ -2110,82 +821,6 @@ WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- -Chambers of Commerce Root - 2008 -================================ ------BEGIN CERTIFICATE----- -MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD -MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv -bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu -QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy -Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl -ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF -EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl -cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA -XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj -h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ -ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk -NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g -D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 -lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ -0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj -ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 -EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI -G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ -BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh -bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh -bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC -CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH -AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 -wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH -3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU -RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 -M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 -YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF -9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK -zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG -nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg -OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ ------END CERTIFICATE----- - -Global Chambersign Root - 2008 -============================== ------BEGIN CERTIFICATE----- -MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD -MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv -bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu -QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx -NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg -Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ -QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD -aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf -VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf -XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 -ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB -/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA -TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M -H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe -Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF -HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh -wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB -AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT -BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE -BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm -aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm -aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp -1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 -dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG -/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 -ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s -dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg -9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH -foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du -qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr -P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq -c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z -09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B ------END CERTIFICATE----- - Go Daddy Root Certificate Authority - G2 ======================================== -----BEGIN CERTIFICATE----- @@ -2360,72 +995,6 @@ 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- -Certinomis - Autorité Racine -============================= ------BEGIN CERTIFICATE----- -MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK -Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg -LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG -A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw -JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa -wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly -Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw -2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N -jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q -c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC -lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb -xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g -530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna -4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ -KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x -WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva -R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 -nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B -CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv -JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE -qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b -WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE -wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ -vgt2Fl43N+bYdJeimUV5 ------END CERTIFICATE----- - -Root CA Generalitat Valenciana -============================== ------BEGIN CERTIFICATE----- -MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE -ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 -IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 -WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE -CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 -F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B -ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ -D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte -JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB -AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n -dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB -ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl -AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA -YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy -AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA -aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt -AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA -YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu -AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA -OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 -dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV -BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G -A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S -b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh -TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz -Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 -NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH -iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt -+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= ------END CERTIFICATE----- - TWCA Root Certification Authority ================================= -----BEGIN CERTIFICATE----- @@ -2553,96 +1122,6 @@ vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- -Trustis FPS Root CA -=================== ------BEGIN CERTIFICATE----- -MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG -EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 -IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV -BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ -RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk -H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa -cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt -o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA -AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd -BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c -GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC -yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P -8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV -l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl -iB6XzCGcKQENZetX2fNXlrtIzYE= ------END CERTIFICATE----- - -StartCom Certification Authority -================================ ------BEGIN CERTIFICATE----- -MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN -U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu -ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 -NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk -LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg -U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y -o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ -Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d -eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt -2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z -6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ -osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ -untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc -UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT -37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ -Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 -dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu -c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv -bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 -aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t -L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG -cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 -fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm -N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN -Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T -tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX -e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA -2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs -HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE -JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib -D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= ------END CERTIFICATE----- - -StartCom Certification Authority G2 -=================================== ------BEGIN CERTIFICATE----- -MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN -U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE -ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O -o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG -4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi -Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul -Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs -O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H -vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L -nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS -FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa -z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ -KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K -2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk -J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ -JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG -/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc -nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld -blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc -l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm -7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm -obp573PYtlNXLfbQ4ddI ------END CERTIFICATE----- - Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- @@ -2725,55 +1204,6 @@ e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== -----END CERTIFICATE----- -EE Certification Centre Root CA -=============================== ------BEGIN CERTIFICATE----- -MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG -EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy -dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw -MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB -UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy -ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM -TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 -rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw -93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN -P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ -MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF -BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj -xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM -lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u -uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU -3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM -dcGWxZ0= ------END CERTIFICATE----- - -TURKTRUST Certificate Services Provider Root 2007 -================================================= ------BEGIN CERTIFICATE----- -MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP -MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg -QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X -DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl -a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN -BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp -bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N -YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv -KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya -KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT -rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC -AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s -Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I -aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO -Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb -BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK -poRq0Tl9 ------END CERTIFICATE----- - D-TRUST Root Class 3 CA 2 2009 ============================== -----BEGIN CERTIFICATE----- @@ -2823,171 +1253,6 @@ w9y4AyHqnxbxLFS1 -----END CERTIFICATE----- -PSCProcert -========== ------BEGIN CERTIFICATE----- -MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk -ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ -MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz -dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl -cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw -IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw -MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w -DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD -ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp -Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC -wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA -3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh -RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO -EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 -0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH -0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU -td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw -Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp -r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ -AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz -Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId -xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp -ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH -EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h -Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k -ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG -9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG -MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG -LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 -ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy -YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v -Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o -dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq -T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN -g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q -uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 -n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn -FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo -5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq -3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 -poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y -eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km ------END CERTIFICATE----- - -China Internet Network Information Center EV Certificates Root -============================================================== ------BEGIN CERTIFICATE----- -MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D -aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg -Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG -A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM -PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl -cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y -jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV -98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H -klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 -KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC -7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD -glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 -0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM -7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws -ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 -5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= ------END CERTIFICATE----- - -Swisscom Root CA 2 -================== ------BEGIN CERTIFICATE----- -MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG -EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy -dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 -MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln -aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC -IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM -LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo -ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ -wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH -Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a -SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS -NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab -mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY -Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 -qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw -HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O -BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu -MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO -v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ -82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz -o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs -a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx -OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW -mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o -+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC -rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX -5OfNeOI5wSsSnqaeG8XmDtkx2Q== ------END CERTIFICATE----- - -Swisscom Root EV CA 2 -===================== ------BEGIN CERTIFICATE----- -MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE -BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl -cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN -MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT -HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg -Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz -o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy -Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti -GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li -qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH -Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG -alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa -m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox -bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi -xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED -MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB -bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL -j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU -wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 -XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH -59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ -23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq -J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA -HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi -uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW -l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= ------END CERTIFICATE----- - -CA Disig Root R1 -================ ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw -EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp -ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx -EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp -c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy -3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 -u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 -m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk -CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa -YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 -vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL -LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX -ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is -XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ -04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR -xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B -LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM -CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb -VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 -YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS -ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix -lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N -UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ -a7+h89n07eLw4+1knj0vllJPgFOL ------END CERTIFICATE----- - CA Disig Root R2 ================ -----BEGIN CERTIFICATE----- @@ -3391,66 +1656,6 @@ 82Z+ -----END CERTIFICATE----- -WoSign -====== ------BEGIN CERTIFICATE----- -MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG -EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g -QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ -BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA -vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO -CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX -2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5 -KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR -+ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez -EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk -lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2 -8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY -yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C -AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R -8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1 -LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq -T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj -y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC -2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes -5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/ -EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh -mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx -kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi -kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w== ------END CERTIFICATE----- - -WoSign China -============ ------BEGIN CERTIFICATE----- -MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG -EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv -geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD -VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k -8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5 -uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85 -dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5 -Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy -b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc -76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m -+Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6 -yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX -GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA -A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6 -yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY -r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115 -j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A -kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97 -qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y -jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB -ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv -T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO -kI26oQ== ------END CERTIFICATE----- - COMODO RSA Certification Authority ================================== -----BEGIN CERTIFICATE----- @@ -3561,36 +1766,6 @@ yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- -Staat der Nederlanden Root CA - G3 -================================== ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE -CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g -Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC -TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l -ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y -olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t -x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy -EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K -Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur -mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5 -1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp -07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo -FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE -41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu -yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD -U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq -KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1 -v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA -8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b -8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r -mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq -1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI -JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV -tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk= ------END CERTIFICATE----- - Staat der Nederlanden EV Root CA ================================ -----BEGIN CERTIFICATE----- @@ -3755,85 +1930,6 @@ ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE----- -TÃœRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H5 -========================================================= ------BEGIN CERTIFICATE----- -MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN -BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp -bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg -RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw -ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w -SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE -n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp -ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537 -jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m -ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP -9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV -4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH -HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI -hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo -BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq -URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl -lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8 -B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU= ------END CERTIFICATE----- - -TÃœRKTRUST Elektronik Sertifika Hizmet SaÄŸlayıcısı H6 -========================================================= ------BEGIN CERTIFICATE----- -MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQGEwJUUjEPMA0G -A1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls -acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5 -MDQxMFoXDTIzMTIxNjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBL -BgNVBAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSf -aSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2VydGlm -aWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCdsGjW6L0UlqMACprx9MfMkU1xeHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a -2uqsxgbPJQ1BgfbBOCK9+bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EED -wnS3/faAz1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0pu5Fb -HH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6plVxiSvgNZ1GpryHV -+DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMBAAGjQjBAMB0GA1UdDgQWBBTdVRcT -9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG -9w0BAQsFAAOCAQEAb1gNl0OqFlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3R -fdCaqaXKGDsCQC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy -o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKIDgI6tflEATseW -hvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm9ocJV612ph1jmv3XZch4gyt1 -O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsGtAuYSyher4hYyw== ------END CERTIFICATE----- - -Certinomis - Root CA -==================== ------BEGIN CERTIFICATE----- -MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK -Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg -LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx -EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD -ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos -P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo -d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap -z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00 -8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x -RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE -6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t -FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV -PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH -i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj -YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I -6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF -AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV -WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw -Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX -lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ -y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9 -Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng -DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi -I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM -cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr -hkIGuUE= ------END CERTIFICATE----- - OISTE WISeKey Global Root GB CA =============================== -----BEGIN CERTIFICATE----- @@ -3856,38 +1952,1281 @@ Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= -----END CERTIFICATE----- -Certification Authority of WoSign G2 -==================================== +SZAFIR ROOT CA2 +=============== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV +BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ +BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD +VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q +qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK +DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE +2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ +ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi +ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC +AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 +O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 +oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul +4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 ++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +=========================== +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE +BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 +bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y +ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ +TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB +IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 +7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o +CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b +Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p +uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 +GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ +9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB +Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye +hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM +BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI +hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW +Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA +L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo +clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM +pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb +w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo +J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm +ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX +is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 +zAYspsbiDrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +======================================================= +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT +BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 +aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx +MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg +QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV +BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw +MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv +bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh +iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ +6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd +FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr +i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F +GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 +fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu +iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI +hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ +D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM +d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y +d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn +82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb +davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F +Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt +J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa +JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q +p/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +=========================================================== +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 +aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw +MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj +IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD +VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 +Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP +dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK +Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA +GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn +dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +ISRG Root X1 +============ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE +BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD +EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG +EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT +DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r +Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 +3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K +b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN +Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ +4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf +1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu +hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH +usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r +OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY +9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV +0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt +hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw +TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx +e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA +JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD +YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n +JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ +m+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +================ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT +AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw +MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD +TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf +qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr +btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL +j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou +08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw +WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT +tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ +47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC +ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa +i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o +dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s +D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ +j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT +Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW ++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 +Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d +8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm +5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG +rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +================ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 +MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH +FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ +gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t +dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce +VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 +DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM +CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy +8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa +2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 +xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +================ +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 +MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 +kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp +N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 +AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd +fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx +kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS +btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 +Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN +c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ +3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw +DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA +A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE +YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW +xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ +gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW +aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV +Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 +KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi +JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +================ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB +f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr +Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 +rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc +eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +================ +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN +/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri +83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA +MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 +AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT +D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr +IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g +TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp +ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD +VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt +c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth +bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 +IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 +6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc +wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 +3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 +WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU +ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc +lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R +e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j +q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +====================== +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw +BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD +DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow +YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs +AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p +OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr +pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ +9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ +xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM +R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ +D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 +oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx +9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 +H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 +6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd ++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ +HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD +F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ +8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv +/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT +aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +TrustCor RootCert CA-1 +====================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx +MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu +YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe +VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy +dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq +jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4 +pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0 +JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h +gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw +/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j +BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5 +mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C +qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P +3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +TrustCor RootCert CA-2 +====================== +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w +DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT +eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0 +eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy +MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h +bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0 +IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb +ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk +RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1 +oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb +XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1 +/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q +jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP +eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg +rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU +2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h +Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp +kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv +2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3 +S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw +PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv +DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU +RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE +xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX +RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ +-----END CERTIFICATE----- + +TrustCor ECA-1 +============== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw +N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5 +MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y +IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR +MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23 +xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc +p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+ +fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj +YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL +f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF +AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u +/ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs +J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC +jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +======================================== +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM +BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x +MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw +MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM +LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C +Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 +P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge +oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp +k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z +fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ +gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 +UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 +1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s +bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr +dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf +ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl +u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq +erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj +MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ +vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI +Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y +wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI +WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +======================================== +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv +BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy +MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO +BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ +8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR +hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT +jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW +e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z +5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +============================================== +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w +DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u +MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD +VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh +hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w +cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO +Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ +B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh +CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim +9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto +RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm +JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 ++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp +qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 +++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx +Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G +guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz +OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 +CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq +lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR +rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 +hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX +9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +=========================================== +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy +BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw +MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM +LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy +3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O +BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe +5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ +N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm +m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +GlobalSign Root CA - R6 +======================= +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX +R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i +YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs +U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss +grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE +3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF +vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM +PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ +azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O +WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy +CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP +0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN +b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV +HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 +lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY +BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym +Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr +3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 +0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T +uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK +oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t +JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GC CA +=============================== +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD +SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo +MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa +Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL +ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr +VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab +NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E +AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk +AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +GTS Root R1 +=========== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG +EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv +b3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG +A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx +9vaMf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7r +aKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnW +r4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqM +LnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly +4cpk9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr +06zqkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om +3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNu +JLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEM +BQADggIBADiWCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6ZXPYfcX3v73sv +fuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZRgyFmxhE+885H7pwoHyXa/6xm +ld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9b +gsiG1eGZbYwE8na6SfZu6W0eX6DvJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq +4BjFbkerQUIpm/ZgDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWEr +tXvM+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyyF62ARPBo +pY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9SQ98POyDGCBDTtWTurQ0 +sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdwsE3PYJ/HQcu51OyLemGhmW/HGY0dVHLql +CFF1pkgl +-----END CERTIFICATE----- + +GTS Root R2 +=========== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQG +EwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJv +b3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAG +A1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTuk +k3LvCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo +7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWI +m8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5Gm +dFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbu +ak7MkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscsz +cTJGr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73Vululycsl +aVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy +5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEM +BQADggIBALZp8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiTz9D2PGcDFWEJ ++YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiApJiS4wGWAqoC7o87xdFtCjMw +c3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvbpxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3Da +WsYDQvTtN6LwG1BUSw7YhN4ZKJmBR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5r +n/WkhLx3+WuXrD5RRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56Gtmwfu +Nmsk0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC5AwiWVIQ +7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiFizoHCBy69Y9Vmhh1fuXs +gWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLnyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ld +o/DUhgkC +-----END CERTIFICATE----- + +GTS Root R3 +=========== -----BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG -EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g -QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx -CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai -XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du -W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9 -5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK -v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC -AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI -hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY -P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3 -TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu -+sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+ -7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg= +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUU +Rout736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24Cej +QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP +0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFukfCPAlaUs3L6JbyO5o91lAFJekazInXJ0 +glMLfalAvWhgxeG4VDvBNhcl2MG9AjEAnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOa +KaqW04MjyaR7YbPMAuhd -----END CERTIFICATE----- -CA WoSign ECC Root +GTS Root R4 +=========== +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa +6zzuhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqj +QjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV +2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0CMRw3J5QdCHojXohw0+WbhXRIjVhLfoI +N+4Zba3bssx9BzT1YBkstTTZbyACMANxsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11x +zPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- + +UCA Global G2 Root ================== -----BEGIN CERTIFICATE----- -MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD -TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v -dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK -ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI -zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU -t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw -QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R -MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0 -Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu -a/GRspBl9JrmkO5K +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x +NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU +cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT +oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV +8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS +h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o +LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ +R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe +KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa +4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc +OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 +8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo +5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A +Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 +yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX +c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo +jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk +bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x +ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn +RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== +-----END CERTIFICATE----- + +UCA Extended Validation Root +============================ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u +IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G +A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs +iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF +Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu +eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR +59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH +0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR +el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv +B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth +WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS +NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS +3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM +aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 +dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb ++7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW +F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi +GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc +GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi +djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr +dhh2n1ax +-----END CERTIFICATE----- + +Certigna Root CA +================ +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE +BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ +MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda +MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz +MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX +stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz +KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 +JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 +XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq +4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej +wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ +lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI +jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ +/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy +dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h +LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl +cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt +OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP +TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq +7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 +4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd +8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS +6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY +tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS +aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde +E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +emSign Root CA - G1 +=================== +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET +MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl +ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx +ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk +aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN +LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 +cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW +DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ +6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH +hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 +vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q +NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q ++Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih +U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +emSign ECC Root CA - G3 +======================= +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG +A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg +MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 +MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 +ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc +58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr +MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D +CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 +jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +emSign Root CA - C1 +=================== +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx +EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp +Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD +ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up +ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ +Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX +OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V +I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms +lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ +XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD +ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp +/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 +NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 +wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ +BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +emSign ECC Root CA - C3 +======================= +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG +A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF +Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD +ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd +6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 +SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA +B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA +MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU +ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 3 +======================= +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG +A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK +Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 +MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv +bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX +SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz +iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf +jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim +5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe +sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj +0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ +JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u +y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h ++bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG +xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID +AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN +AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw +W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld +y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov ++BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc +eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw +9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 +nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY +hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB +60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq +dBb9HxEGmpv0 +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G4 +========================================= +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu +bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1 +dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT +AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D +umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV +3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds +8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ +e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7 +ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X +xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV +7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW +Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n +MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q +jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht +7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK +YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt +jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+ +m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW +RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA +JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G ++TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT +kcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +Microsoft ECC Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND +IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 +MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 +thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB +eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM ++Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf +Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR +eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +Microsoft RSA Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg +UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw +NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u +MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml +7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e +S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 +1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ +dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F +yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS +MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr +lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ +0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ +ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og +6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 +dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk ++ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex +/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy +AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW +ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE +7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT +c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D +5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +e-Szigno Root CA 2017 +===================== +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw +DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt +MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa +Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE +CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp +Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx +s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv +vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA +tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO +svxyqltZ+efcMQ== +-----END CERTIFICATE----- + +certSIGN Root CA G2 +=================== +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw +EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy +MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH +TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 +N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk +abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg +wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp +dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh +ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 +jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf +95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc +z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL +iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB +ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB +/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 +8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 +BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW +atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU +Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M +NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N +0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +Trustwave Global Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 +zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf +LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq +stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o +WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ +OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 +Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE +uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm ++9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj +ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB +BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H +PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H +ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla +4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R +vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd +zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O +856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH +Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu +3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP +29FpHOTKyeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +Trustwave Global ECC P256 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 +NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj +43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm +P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt +0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz +RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +Trustwave Global ECC P384 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 +NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH +Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr +/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV +HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn +ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl +CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== +-----END CERTIFICATE----- + +NAVER Global Root Certification Authority +========================================= +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG +A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD +DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 +NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT +UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb +UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW ++j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 +XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 +aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 +Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z +VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B +A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai +cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy +YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV +HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK +21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB +jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx +hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg +E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH +D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ +A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY +qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG +I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg +kpzNNIaRkPpkUZ3+/uul9XXeifdy +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM SERVIDORES SEGUROS +=================================== +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF +UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy +NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 +MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt +UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB +QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 +LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG +SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD +zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= +-----END CERTIFICATE----- + +GlobalSign Root R46 +=================== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv +b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX +BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es +CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ +r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje +2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt +bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj +K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 +12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on +ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls +eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 +vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM +BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy +gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 +CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm +OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq +JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye +qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz +nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 +DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 +QEUxeCp6 +-----END CERTIFICATE----- + +GlobalSign Root E46 +=================== +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT +AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg +RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV +BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB +jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj +QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL +gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk +vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ +CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +TunTrust Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG +A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj +dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw +NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD +ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz +2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b +bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 +NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd +gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW +VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f +Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ +juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas +DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS +VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI +04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl +0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd +Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY +YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp +adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x +xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP +jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM +MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z +ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r +AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +HARICA TLS RSA Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG +EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz +OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl +bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB +IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN +JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu +a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y +Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K +5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv +dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR +0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH +GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm +haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ +CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU +EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq +QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD +QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR +j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 +vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 +qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 +Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ +PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn +kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= +-----END CERTIFICATE----- + +HARICA TLS ECC Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH +UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD +QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX +DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj +IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv +b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l +AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b +ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW +0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi +rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw +CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps -----END CERTIFICATE----- diff -Nru phabricator-0~git20200925/arcanist/scripts/arcanist.php phabricator-0~git20220903/arcanist/scripts/arcanist.php --- phabricator-0~git20200925/arcanist/scripts/arcanist.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/scripts/arcanist.php 2022-05-17 23:15:03.000000000 +0000 @@ -68,7 +68,10 @@ array( 'name' => 'conduit-uri', 'param' => 'uri', - 'help' => pht('Connect to Phabricator install specified by __uri__.'), + 'help' => pht( + 'Connect to the %s (or compatible software) server specified by '. + '__uri__.', + PlatformSymbols::getPlatformServerName()), ), array( 'name' => 'conduit-token', @@ -85,7 +88,8 @@ 'repeat' => true, 'help' => pht( 'Specify a runtime configuration value. This will take precedence '. - 'over static values, and only affect the current arcanist invocation.'), + 'over static values, and only affect the current process: the '. + 'setting is not saved anywhere.'), ), )); @@ -310,9 +314,13 @@ $message = phutil_console_format( "%s\n\n - %s\n - %s\n - %s\n", pht( - 'This command requires arc to connect to a Phabricator install, '. - 'but no Phabricator installation is configured. To configure a '. - 'Phabricator URI:'), + 'This command requires %s to connect to a %s (or compatible '. + 'software) server, but no %s server is configured. To configure a '. + '%s server URI:', + PlatformSymbols::getPlatformClientName(), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName()), pht( 'set a default location with `%s`; or', 'arc set-config default '), @@ -688,10 +696,12 @@ "** %s ** %s\n", pht('VERY META'), pht( - 'You are running one copy of Arcanist (at path "%s") against '. - 'another copy of Arcanist (at path "%s"). Code in the current '. + 'You are running one copy of %s (at path "%s") against '. + 'another copy of %s (at path "%s"). Code in the current '. 'working directory will not be loaded or executed.', + PlatformSymbols::getPlatformClientName(), $executing_directory, + PlatformSymbols::getPlatformClientName(), $working_directory))); } } diff -Nru phabricator-0~git20200925/arcanist/src/conduit/ArcanistConduitEngine.php phabricator-0~git20220903/arcanist/src/conduit/ArcanistConduitEngine.php --- phabricator-0~git20200925/arcanist/src/conduit/ArcanistConduitEngine.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/conduit/ArcanistConduitEngine.php 2022-05-17 23:15:03.000000000 +0000 @@ -89,8 +89,8 @@ $block = id(new PhutilConsoleBlock()) ->addParagraph( pht( - 'This command needs to communicate with Phabricator, but no '. - 'Phabricator URI is configured.')) + 'This command needs to communicate with a server, but no '. + 'server URI is configured.')) ->addList($list); throw new ArcanistUsageException($block->drawConsoleString()); diff -Nru phabricator-0~git20200925/arcanist/src/config/arc/ArcanistArcConfigurationEngineExtension.php phabricator-0~git20220903/arcanist/src/config/arc/ArcanistArcConfigurationEngineExtension.php --- phabricator-0~git20200925/arcanist/src/config/arc/ArcanistArcConfigurationEngineExtension.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/config/arc/ArcanistArcConfigurationEngineExtension.php 2022-05-17 23:15:03.000000000 +0000 @@ -71,10 +71,10 @@ ->setSummary(pht('Repository for the current working copy.')) ->setHelp( pht( - 'Associate the working copy with a specific Phabricator '. - 'repository. Normally, Arcanist can figure this association '. - 'out on its own, but if your setup is unusual you can use '. - 'this option to tell it what the desired value is.')) + 'Associate the working copy with a specific repository. Normally, '. + 'this association can be determined automatically, but if your '. + 'setup is unusual you can use this option to tell it what the '. + 'desired value is.')) ->setExamples( array( 'libexample', @@ -89,14 +89,15 @@ 'conduit_uri', 'default', )) - ->setSummary(pht('Phabricator install to connect to.')) + ->setSummary(pht('Server to connect to.')) ->setHelp( pht( 'Associates this working copy with a specific installation of '. - 'Phabricator.')) + '%s (or compatible software).', + PlatformSymbols::getPlatformServerName())) ->setExamples( array( - 'https://phabricator.mycompany.com/', + 'https://devtools.example.com/', )), id(new ArcanistAliasesConfigOption()) ->setKey(self::KEY_ALIASES) diff -Nru phabricator-0~git20200925/arcanist/src/config/source/ArcanistFilesystemConfigurationSource.php phabricator-0~git20220903/arcanist/src/config/source/ArcanistFilesystemConfigurationSource.php --- phabricator-0~git20200925/arcanist/src/config/source/ArcanistFilesystemConfigurationSource.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/config/source/ArcanistFilesystemConfigurationSource.php 2022-05-17 23:15:03.000000000 +0000 @@ -39,7 +39,20 @@ $content = id(new PhutilJSON()) ->encodeFormatted($values); - Filesystem::writeFile($this->path, $content); + $path = $this->path; + + // If the containing directory does not exist yet, create it. + // + // This is expected when (for example) you first write to project + // configuration in a Git working copy: the ".git/arc" directory will + // not exist yet. + + $dir = dirname($path); + if (!Filesystem::pathExists($dir)) { + Filesystem::createDirectory($dir, 0755, $recursive = true); + } + + Filesystem::writeFile($path, $content); } } diff -Nru phabricator-0~git20200925/arcanist/src/configuration/ArcanistBlindlyTrustHTTPEngineExtension.php phabricator-0~git20220903/arcanist/src/configuration/ArcanistBlindlyTrustHTTPEngineExtension.php --- phabricator-0~git20200925/arcanist/src/configuration/ArcanistBlindlyTrustHTTPEngineExtension.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/configuration/ArcanistBlindlyTrustHTTPEngineExtension.php 2022-05-17 23:15:03.000000000 +0000 @@ -15,7 +15,7 @@ } public function getExtensionName() { - return pht('Arcanist HTTPS Trusted Domains'); + return pht('HTTPS Trusted Domains'); } public function shouldTrustAnySSLAuthorityForURI(PhutilURI $uri) { diff -Nru phabricator-0~git20200925/arcanist/src/configuration/ArcanistConfigurationManager.php phabricator-0~git20220903/arcanist/src/configuration/ArcanistConfigurationManager.php --- phabricator-0~git20200925/arcanist/src/configuration/ArcanistConfigurationManager.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/configuration/ArcanistConfigurationManager.php 2022-05-17 23:15:03.000000000 +0000 @@ -258,7 +258,7 @@ } public function getUserConfigurationFileLocation() { - if (strlen($this->customArcrcFilename)) { + if ($this->customArcrcFilename !== null) { return $this->customArcrcFilename; } diff -Nru phabricator-0~git20200925/arcanist/src/configuration/ArcanistSettings.php phabricator-0~git20220903/arcanist/src/configuration/ArcanistSettings.php --- phabricator-0~git20200925/arcanist/src/configuration/ArcanistSettings.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/configuration/ArcanistSettings.php 2022-05-17 23:15:03.000000000 +0000 @@ -7,11 +7,11 @@ 'default' => array( 'type' => 'string', 'help' => pht( - 'The URI of a Phabricator install to connect to by default, if '. - '%s is run in a project without a Phabricator URI or run outside '. + 'The URI of a server to connect to by default, if '. + '%s is run in a project without a configured URI or run outside '. 'of a project.', 'arc'), - 'example' => '"http://phabricator.example.com/"', + 'example' => '"http://devtools.example.com/"', ), 'base' => array( 'type' => 'string', @@ -35,7 +35,7 @@ 'type' => 'string', 'example' => '"X"', 'help' => pht( - 'Associate the working copy with a specific Phabricator repository. '. + 'Associate the working copy with a specific repository. '. 'Normally, %s can figure this association out on its own, but if '. 'your setup is unusual you can use this option to tell it what the '. 'desired value is.', @@ -44,10 +44,9 @@ 'phabricator.uri' => array( 'type' => 'string', 'legacy' => 'conduit_uri', - 'example' => '"https://phabricator.mycompany.com/"', + 'example' => '"https://devtools.example.com/"', 'help' => pht( - 'Associates this working copy with a specific installation of '. - 'Phabricator.'), + 'Associates this working copy with a specific server.'), ), 'lint.engine' => array( 'type' => 'string', @@ -96,8 +95,8 @@ 'https.cabundle' => array( 'type' => 'string', 'help' => pht( - "Path to a custom CA bundle file to be used for arcanist's cURL ". - "calls. This is used primarily when your conduit endpoint is ". + "Path to a custom CA bundle file to be used for cURL calls. ". + "This is used primarily when your conduit endpoint is ". "behind HTTPS signed by your organization's internal CA."), 'example' => 'support/yourca.pem', ), @@ -118,7 +117,7 @@ 'Whether %s should permit the automatic stashing of changes in the '. 'working directory when requiring a clean working copy. This option '. 'should only be used when users understand how to restore their '. - 'working directory from the local stash if an Arcanist operation '. + 'working directory from the local stash if an operation '. 'causes an unrecoverable error.', 'arc'), 'default' => false, diff -Nru phabricator-0~git20200925/arcanist/src/console/PhutilConsoleFormatter.php phabricator-0~git20220903/arcanist/src/console/PhutilConsoleFormatter.php --- phabricator-0~git20200925/arcanist/src/console/PhutilConsoleFormatter.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/console/PhutilConsoleFormatter.php 2022-05-17 23:15:03.000000000 +0000 @@ -22,23 +22,38 @@ public static function getDisableANSI() { if (self::$disableANSI === null) { - $term = phutil_utf8_strtolower(getenv('TERM')); - // ansicon enables ANSI support on Windows - if (!$term && getenv('ANSICON')) { - $term = 'ansi'; + self::$disableANSI = self::newShouldDisableAnsi(); + } + return self::$disableANSI; + } + + private static function newShouldDisableANSI() { + $term = phutil_utf8_strtolower(getenv('TERM')); + + // ansicon enables ANSI support on Windows + if (!$term && getenv('ANSICON')) { + $term = 'ansi'; + } + + + if (phutil_is_windows()) { + if ($term !== 'cygwin' && $term !== 'ansi') { + return true; } + } + + $stdout = PhutilSystem::getStdoutHandle(); + if ($stdout === null) { + return true; + } - if (phutil_is_windows() && $term !== 'cygwin' && $term !== 'ansi') { - self::$disableANSI = true; - } else if (!defined('STDOUT')) { - self::$disableANSI = true; - } else if (function_exists('posix_isatty') && !posix_isatty(STDOUT)) { - self::$disableANSI = true; - } else { - self::$disableANSI = false; + if (function_exists('posix_isatty')) { + if (!posix_isatty($stdout)) { + return true; } } - return self::$disableANSI; + + return false; } public static function formatString($format /* ... */) { diff -Nru phabricator-0~git20200925/arcanist/src/console/PhutilInteractiveEditor.php phabricator-0~git20220903/arcanist/src/console/PhutilInteractiveEditor.php --- phabricator-0~git20200925/arcanist/src/console/PhutilInteractiveEditor.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/console/PhutilInteractiveEditor.php 2022-05-17 23:15:03.000000000 +0000 @@ -22,6 +22,7 @@ private $offset = 0; private $preferred; private $fallback; + private $taskMessage; /* -( Creating a New Editor )---------------------------------------------- */ @@ -74,6 +75,20 @@ $editor = $this->getEditor(); $offset = $this->getLineOffset(); + $binary = basename($editor); + + // This message is primarily an assistance to users with GUI-based + // editors configured. Users with terminal-based editors won't have a + // chance to see this prior to the editor being launched. + echo tsprintf( + "%s\n", + pht('Launching editor "%s"...', $binary)); + + $task_message = $this->getTaskMessage(); + if ($task_message !== null) { + echo tsprintf("%s\n", $task_message); + } + $err = $this->invokeEditor($editor, $path, $offset); if ($err) { @@ -85,7 +100,6 @@ 'vim' => true, ); - $binary = basename($editor); if (isset($vi_binaries[$binary])) { // This runs "Q" (an invalid command), then "q" (a valid command, // meaning "quit"). Vim binaries with behavior that makes them poor @@ -266,6 +280,33 @@ return $this; } + /** + * Set the message that identifies the task for which the editor is being + * launched, displayed to the user prior to it being launched. + * + * @param string The message to display to the user. + * @return $this + * + * @task config + */ + public function setTaskMessage($task_message) { + $this->taskMessage = $task_message; + return $this; + } + + /** + * Retrieve the current message that will display to the user just prior to + * invoking the editor. + * + * @return string The message that will display to the user, or null if no + * message will be displayed. + * + * @task config + */ + public function getTaskMessage() { + return $this->taskMessage; + } + /** * Get the name of the editor program to use. The value of the environmental diff -Nru phabricator-0~git20200925/arcanist/src/differential/ArcanistDifferentialCommitMessage.php phabricator-0~git20220903/arcanist/src/differential/ArcanistDifferentialCommitMessage.php --- phabricator-0~git20200925/arcanist/src/differential/ArcanistDifferentialCommitMessage.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/differential/ArcanistDifferentialCommitMessage.php 2022-05-17 23:15:03.000000000 +0000 @@ -139,10 +139,10 @@ throw new ArcanistUsageException( pht( 'Invalid "Differential Revision" field in commit message. This field '. - 'should have a revision identifier like "%s" or a Phabricator URI '. + 'should have a revision identifier like "%s" or a server URI '. 'like "%s", but has "%s".', 'D123', - 'https://phabricator.example.com/D123', + 'https://devtools.example.com/D123', $revision_value)); } diff -Nru phabricator-0~git20200925/arcanist/src/error/PhutilErrorHandler.php phabricator-0~git20220903/arcanist/src/error/PhutilErrorHandler.php --- phabricator-0~git20200925/arcanist/src/error/PhutilErrorHandler.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/error/PhutilErrorHandler.php 2022-05-17 23:15:03.000000000 +0000 @@ -180,10 +180,9 @@ * @return void * @task internal */ - public static function handleError($num, $str, $file, $line, $ctx) { - + public static function handleError($num, $str, $file, $line, $ctx = null) { foreach (self::$traps as $trap) { - $trap->addError($num, $str, $file, $line, $ctx); + $trap->addError($num, $str, $file, $line); } if ((error_reporting() & $num) == 0) { @@ -214,7 +213,6 @@ array( 'file' => $file, 'line' => $line, - 'context' => $ctx, 'error_code' => $num, 'trace' => $trace, )); @@ -379,7 +377,7 @@ * @task internal */ public static function dispatchErrorMessage($event, $value, $metadata) { - $timestamp = strftime('%Y-%m-%d %H:%M:%S'); + $timestamp = date('Y-m-d H:i:s'); switch ($event) { case self::ERROR: @@ -428,16 +426,6 @@ $metadata['default_message'] = $default_message; error_log($default_message); - break; - case self::DEPRECATED: - $default_message = sprintf( - '[%s] DEPRECATED: %s is deprecated; %s', - $timestamp, - $value, - $metadata['why']); - - $metadata['default_message'] = $default_message; - error_log($default_message); break; default: error_log(pht('Unknown event %s', $event)); diff -Nru phabricator-0~git20200925/arcanist/src/error/PhutilErrorTrap.php phabricator-0~git20220903/arcanist/src/error/PhutilErrorTrap.php --- phabricator-0~git20200925/arcanist/src/error/PhutilErrorTrap.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/error/PhutilErrorTrap.php 2022-05-17 23:15:03.000000000 +0000 @@ -41,13 +41,12 @@ private $destroyed; private $errors = array(); - public function addError($num, $str, $file, $line, $ctx) { + public function addError($num, $str, $file, $line) { $this->errors[] = array( 'num' => $num, 'str' => $str, 'file' => $file, 'line' => $line, - 'ctx' => $ctx, ); return $this; } diff -Nru phabricator-0~git20200925/arcanist/src/exception/PhutilRegexException.php phabricator-0~git20220903/arcanist/src/exception/PhutilRegexException.php --- phabricator-0~git20200925/arcanist/src/exception/PhutilRegexException.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/exception/PhutilRegexException.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,3 @@ +requireBinaryVersion(), + self::CAPABILITY_TEMPLATE_PNODE); + } + + /** + * The `hg annotate` command did not accept the `--template` argument until + * version 4.6. It appears to function in version 4.5 however it's not + * documented and wasn't announced until the 4.6 release. + * + * @return boolean True if the version of Mercurial is new enough to support + * the `--template` option when using `hg annotate`, or false if otherwise. + */ + public function isMercurialAnnotateTemplatesAvailable() { + return self::versionHasCapability( + $this->requireBinaryVersion(), + self::CAPABILTIY_ANNOTATE_TEMPLATES); + } + public static function versionHasCapability( $mercurial_version, @@ -70,6 +99,10 @@ return version_compare($mercurial_version, '3.2', '>='); case self::CAPABILITY_INJECTION: return version_compare($mercurial_version, '3.2.4', '<'); + case self::CAPABILITY_TEMPLATE_PNODE: + return version_compare($mercurial_version, '4.9', '>='); + case self::CAPABILTIY_ANNOTATE_TEMPLATES: + return version_compare($mercurial_version, '4.6', '>='); default: throw new Exception( pht( diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/Filesystem.php phabricator-0~git20220903/arcanist/src/filesystem/Filesystem.php --- phabricator-0~git20200925/arcanist/src/filesystem/Filesystem.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/Filesystem.php 2022-05-17 23:15:03.000000000 +0000 @@ -52,7 +52,7 @@ * Make assertions about the state of path in preparation for * writeFile() and writeFileIfChanged(). */ - private static function assertWritableFile($path) { + public static function assertWritableFile($path) { $path = self::resolvePath($path); $dir = dirname($path); @@ -269,7 +269,29 @@ self::assertReadable($from); if (phutil_is_windows()) { - execx('copy /Y %s %s', $from, $to); + $trap = new PhutilErrorTrap(); + $ok = @copy($from, $to); + $err = $trap->getErrorsAsString(); + $trap->destroy(); + + if (!$ok) { + if (strlen($err)) { + throw new FilesystemException( + $to, + pht( + 'Failed to copy file from "%s" to "%s": %s', + $from, + $to, + $err)); + } else { + throw new FilesystemException( + $to, + pht( + 'Failed to copy file from "%s" to "%s".', + $from, + $to)); + } + } } else { execx('cp -p %s %s', $from, $to); } diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/linesofalarge/LinesOfALarge.php phabricator-0~git20220903/arcanist/src/filesystem/linesofalarge/LinesOfALarge.php --- phabricator-0~git20200925/arcanist/src/filesystem/linesofalarge/LinesOfALarge.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/linesofalarge/LinesOfALarge.php 2022-05-17 23:15:03.000000000 +0000 @@ -212,7 +212,7 @@ if (strlen($this->buf)) { $this->num++; $this->line = $this->buf; - $this->buf = null; + $this->buf = ''; } else { $this->valid = false; } diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/ArcanistHostMemorySnapshot.php phabricator-0~git20220903/arcanist/src/filesystem/memory/ArcanistHostMemorySnapshot.php --- phabricator-0~git20200925/arcanist/src/filesystem/memory/ArcanistHostMemorySnapshot.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/ArcanistHostMemorySnapshot.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,156 @@ +memorySnapshot = $snapshot->readMeminfoSnapshot( + $meminfo_source, + $meminfo_raw); + + return $snapshot; + } + + public function getTotalSwapBytes() { + $info = $this->getMemorySnapshot(); + return $info['swap.total']; + } + + private function getMemorySnapshot() { + if ($this->memorySnapshot === null) { + $this->memorySnapshot = $this->newMemorySnapshot(); + } + + return $this->memorySnapshot; + } + + private function newMemorySnapshot() { + $meminfo_source = '/proc/meminfo'; + list($meminfo_raw) = execx('cat %s', $meminfo_source); + return $this->readMeminfoSnapshot($meminfo_source, $meminfo_raw); + } + + private function readMeminfoSnapshot($meminfo_source, $meminfo_raw) { + $meminfo_pattern = '/^([^:]+):\s+(\S+)(?:\s+(kB))?\z/'; + + $meminfo_map = array(); + + $meminfo_lines = phutil_split_lines($meminfo_raw, false); + foreach ($meminfo_lines as $meminfo_line) { + $meminfo_parts = phutil_preg_match($meminfo_pattern, $meminfo_line); + + if (!$meminfo_parts) { + throw new Exception( + pht( + 'Unable to parse line in meminfo source "%s": "%s".', + $meminfo_source, + $meminfo_line)); + } + + $meminfo_key = $meminfo_parts[1]; + $meminfo_value = $meminfo_parts[2]; + $meminfo_unit = idx($meminfo_parts, 3); + + if (isset($meminfo_map[$meminfo_key])) { + throw new Exception( + pht( + 'Encountered duplicate meminfo key "%s" in meminfo source "%s".', + $meminfo_key, + $meminfo_source)); + } + + $meminfo_map[$meminfo_key] = array( + 'value' => $meminfo_value, + 'unit' => $meminfo_unit, + ); + } + + $swap_total_bytes = $this->readMeminfoBytes( + $meminfo_source, + $meminfo_map, + 'SwapTotal'); + + return array( + 'swap.total' => $swap_total_bytes, + ); + } + + private function readMeminfoBytes( + $meminfo_source, + $meminfo_map, + $meminfo_key) { + + $meminfo_integer = $this->readMeminfoIntegerValue( + $meminfo_source, + $meminfo_map, + $meminfo_key); + + $meminfo_unit = $meminfo_map[$meminfo_key]['unit']; + if ($meminfo_unit === null) { + throw new Exception( + pht( + 'Expected to find a byte unit for meminfo key "%s" in meminfo '. + 'source "%s", found no unit.', + $meminfo_key, + $meminfo_source)); + } + + if ($meminfo_unit !== 'kB') { + throw new Exception( + pht( + 'Expected unit for meminfo key "%s" in meminfo source "%s" '. + 'to be "kB", found "%s".', + $meminfo_key, + $meminfo_source, + $meminfo_unit)); + } + + $meminfo_bytes = ($meminfo_integer * 1024); + + return $meminfo_bytes; + } + + private function readMeminfoIntegerValue( + $meminfo_source, + $meminfo_map, + $meminfo_key) { + + $meminfo_value = $this->readMeminfoValue( + $meminfo_source, + $meminfo_map, + $meminfo_key); + + if (!phutil_preg_match('/^\d+\z/', $meminfo_value)) { + throw new Exception( + pht( + 'Expected to find an integer value for meminfo key "%s" in '. + 'meminfo source "%s", found "%s".', + $meminfo_key, + $meminfo_source, + $meminfo_value)); + } + + return (int)$meminfo_value; + } + + private function readMeminfoValue( + $meminfo_source, + $meminfo_map, + $meminfo_key) { + + if (!isset($meminfo_map[$meminfo_key])) { + throw new Exception( + pht( + 'Expected to find meminfo key "%s" in meminfo source "%s".', + $meminfo_key, + $meminfo_source)); + } + + return $meminfo_map[$meminfo_key]['value']; + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php --- phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,51 @@ + 4294963200, + 'meminfo_swap_zero.txt' => 0, + 'meminfo_swap_missing.txt' => false, + 'meminfo_swap_invalid.txt' => false, + 'meminfo_swap_badunits.txt' => false, + 'meminfo_swap_duplicate.txt' => false, + ); + + $test_dir = dirname(__FILE__).'/data/'; + + foreach ($test_cases as $test_file => $expect) { + $test_data = Filesystem::readFile($test_dir.$test_file); + + $caught = null; + $actual = null; + try { + $snapshot = ArcanistHostMemorySnapshot::newFromRawMeminfo( + $test_file, + $test_data); + $actual = $snapshot->getTotalSwapBytes(); + } catch (Exception $ex) { + if ($expect === false) { + $caught = $ex; + } else { + throw $ex; + } + } catch (Throwable $ex) { + throw $ex; + } + + if ($expect === false) { + $this->assertTrue( + ($caught instanceof Exception), + pht('Expected exception for "%s".', $test_file)); + } else { + $this->assertEqual( + $expect, + $actual, + pht('Result for "%s".', $test_file)); + } + } + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_badunits.txt phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_badunits.txt --- phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_badunits.txt 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_badunits.txt 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,2 @@ +MemTotal: 8140924 kB +SwapTotal: 4194 mB diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_duplicate.txt phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_duplicate.txt --- phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_duplicate.txt 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_duplicate.txt 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,3 @@ +MemTotal: 8140924 kB +SwapTotal: 4194300 kB +SwapTotal: 4194300 kB diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_invalid.txt phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_invalid.txt --- phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_invalid.txt 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_invalid.txt 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,2 @@ +MemTotal: 8140924 kB +SwapTotal: aardvark kB diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_missing.txt phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_missing.txt --- phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_missing.txt 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_missing.txt 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1 @@ +MemTotal: 8140924 kB diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt --- phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,51 @@ +MemTotal: 8140924 kB +MemFree: 1760456 kB +MemAvailable: 4264888 kB +Buffers: 36784 kB +Cached: 2654788 kB +SwapCached: 2132 kB +Active: 331128 kB +Inactive: 5677400 kB +Active(anon): 22692 kB +Inactive(anon): 3325560 kB +Active(file): 308436 kB +Inactive(file): 2351840 kB +Unevictable: 23012 kB +Mlocked: 18476 kB +SwapTotal: 4194300 kB +SwapFree: 2440444 kB +Dirty: 44 kB +Writeback: 0 kB +AnonPages: 3337944 kB +Mapped: 117424 kB +Shmem: 19872 kB +KReclaimable: 124728 kB +Slab: 240640 kB +SReclaimable: 124728 kB +SUnreclaim: 115912 kB +KernelStack: 6736 kB +PageTables: 42044 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 8264760 kB +Committed_AS: 6994880 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 16656 kB +VmallocChunk: 0 kB +Percpu: 9856 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +ShmemHugePages: 0 kB +ShmemPmdMapped: 0 kB +FileHugePages: 0 kB +FilePmdMapped: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +Hugetlb: 0 kB +DirectMap4k: 270336 kB +DirectMap2M: 8118272 kB +DirectMap1G: 1048576 kB diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt --- phabricator-0~git20200925/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,51 @@ +MemTotal: 8140924 kB +MemFree: 1760456 kB +MemAvailable: 4264888 kB +Buffers: 36784 kB +Cached: 2654788 kB +SwapCached: 2132 kB +Active: 331128 kB +Inactive: 5677400 kB +Active(anon): 22692 kB +Inactive(anon): 3325560 kB +Active(file): 308436 kB +Inactive(file): 2351840 kB +Unevictable: 23012 kB +Mlocked: 18476 kB +SwapTotal: 0 kB +SwapFree: 2440444 kB +Dirty: 44 kB +Writeback: 0 kB +AnonPages: 3337944 kB +Mapped: 117424 kB +Shmem: 19872 kB +KReclaimable: 124728 kB +Slab: 240640 kB +SReclaimable: 124728 kB +SUnreclaim: 115912 kB +KernelStack: 6736 kB +PageTables: 42044 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 8264760 kB +Committed_AS: 6994880 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 16656 kB +VmallocChunk: 0 kB +Percpu: 9856 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +ShmemHugePages: 0 kB +ShmemPmdMapped: 0 kB +FileHugePages: 0 kB +FilePmdMapped: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +Hugetlb: 0 kB +DirectMap4k: 270336 kB +DirectMap2M: 8118272 kB +DirectMap1G: 1048576 kB diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/PhutilDirectoryFixture.php phabricator-0~git20220903/arcanist/src/filesystem/PhutilDirectoryFixture.php --- phabricator-0~git20200925/arcanist/src/filesystem/PhutilDirectoryFixture.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/PhutilDirectoryFixture.php 2022-05-17 23:15:03.000000000 +0000 @@ -28,6 +28,8 @@ } public function getPath($to_file = null) { + $to_file = phutil_string_cast($to_file); + return $this->path.'/'.ltrim($to_file, '/'); } diff -Nru phabricator-0~git20200925/arcanist/src/filesystem/PhutilErrorLog.php phabricator-0~git20220903/arcanist/src/filesystem/PhutilErrorLog.php --- phabricator-0~git20200925/arcanist/src/filesystem/PhutilErrorLog.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/filesystem/PhutilErrorLog.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,101 @@ +logName = $log_name; + return $this; + } + + public function getLogName() { + return $this->logName; + } + + public function setLogPath($log_path) { + $this->logPath = $log_path; + return $this; + } + + public function getLogPath() { + return $this->logPath; + } + + public function activateLog() { + $log_path = $this->getLogPath(); + + if ($log_path !== null && false) { + // Test that the path is writable. + $write_exception = null; + try { + Filesystem::assertWritableFile($log_path); + } catch (FilesystemException $ex) { + $write_exception = $ex; + } + + // If we hit an exception, try to create the containing directory. + if ($write_exception) { + $log_dir = dirname($log_path); + if (!Filesystem::pathExists($log_dir)) { + try { + Filesystem::createDirectory($log_dir, 0755, true); + } catch (FilesystemException $ex) { + throw new PhutilProxyException( + pht( + 'Unable to write log "%s" to path "%s". The containing '. + 'directory ("%s") does not exist or is not readable, and '. + 'could not be created.', + $this->getLogName(), + $log_path, + $log_dir), + $ex); + } + } + + // If we created the parent directory, test if the path is writable + // again. + try { + Filesystem::assertWritableFile($log_path); + $write_exception = null; + } catch (FilesystemException $ex) { + $write_exception = $ex; + } + } + + // If we ran into a write exception and couldn't resolve it, fail. + if ($write_exception) { + throw new PhutilProxyException( + pht( + 'Unable to write log "%s" to path "%s" because the path is not '. + 'writable.', + $this->getLogName(), + $log_path), + $write_exception); + } + } + + ini_set('error_log', $log_path); + PhutilErrorHandler::setErrorListener(array($this, 'onError')); + } + + public function onError($event, $value, array $metadata) { + // If we've set "error_log" to a real file, so messages won't be output to + // stderr by default. Copy them to stderr. + + if ($this->logPath === null) { + return; + } + + $message = idx($metadata, 'default_message'); + + if (strlen($message)) { + $message = tsprintf("%B\n", $message); + PhutilSystem::writeStderr($message); + } + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/future/aws/PhutilAWSException.php phabricator-0~git20220903/arcanist/src/future/aws/PhutilAWSException.php --- phabricator-0~git20200925/arcanist/src/future/aws/PhutilAWSException.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/aws/PhutilAWSException.php 2022-05-17 23:15:03.000000000 +0000 @@ -49,4 +49,24 @@ return $this->httpStatus; } + public function isNotFoundError() { + if ($this->hasErrorCode('InvalidVolume.NotFound')) { + return true; + } + + return false; + } + + private function hasErrorCode($code) { + $errors = idx($this->params, 'Errors', array()); + + foreach ($errors as $error) { + if ($error[0] === $code) { + return true; + } + } + + return false; + } + } diff -Nru phabricator-0~git20200925/arcanist/src/future/aws/PhutilAWSFuture.php phabricator-0~git20220903/arcanist/src/future/aws/PhutilAWSFuture.php --- phabricator-0~git20200925/arcanist/src/future/aws/PhutilAWSFuture.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/aws/PhutilAWSFuture.php 2022-05-17 23:15:03.000000000 +0000 @@ -142,6 +142,7 @@ try { $xml = @(new SimpleXMLElement($body)); } catch (Exception $ex) { + phlog($ex); $xml = null; } @@ -155,9 +156,28 @@ ); if ($xml) { $params['RequestID'] = $xml->RequestID[0]; - $errors = array($xml->Error); - foreach ($errors as $error) { - $params['Errors'][] = array($error->Code, $error->Message); + + // NOTE: The S3 and EC2 APIs return slightly different error responses. + + // In S3 responses, there's a simple top-level "" element. + $s3_error = $xml->Error; + if ($s3_error) { + $params['Errors'][] = array( + phutil_string_cast($s3_error->Code), + phutil_string_cast($s3_error->Message), + ); + } + + // In EC2 responses, there's an "" element with "" + // children. + $ec2_errors = $xml->Errors[0]; + if ($ec2_errors) { + foreach ($ec2_errors as $error) { + $params['Errors'][] = array( + phutil_string_cast($error->Code), + phutil_string_cast($error->Message), + ); + } } } diff -Nru phabricator-0~git20200925/arcanist/src/future/exec/ExecFuture.php phabricator-0~git20220903/arcanist/src/future/exec/ExecFuture.php --- phabricator-0~git20200925/arcanist/src/future/exec/ExecFuture.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/exec/ExecFuture.php 2022-05-17 23:15:03.000000000 +0000 @@ -192,14 +192,21 @@ * @task interact */ public function read() { - $stdout = $this->readStdout(); + $stdout_value = $this->readStdout(); + + $stderr = $this->stderr; + if ($stderr === null) { + $stderr_value = ''; + } else { + $stderr_value = substr($stderr, $this->stderrPos); + } $result = array( - $stdout, - (string)substr($this->stderr, $this->stderrPos), + $stdout_value, + $stderr_value, ); - $this->stderrPos = strlen($this->stderr); + $this->stderrPos = $this->getStderrBufferLength(); return $result; } @@ -209,8 +216,16 @@ $this->updateFuture(); // Sync } - $result = (string)substr($this->stdout, $this->stdoutPos); - $this->stdoutPos = strlen($this->stdout); + $stdout = $this->stdout; + + if ($stdout === null) { + $result = ''; + } else { + $result = substr($stdout, $this->stdoutPos); + } + + $this->stdoutPos = $this->getStdoutBufferLength(); + return $result; } @@ -475,7 +490,7 @@ * @task internal */ public function isReadBufferEmpty() { - return !strlen($this->stdout); + return !$this->getStdoutBufferLength(); } @@ -757,14 +772,17 @@ $max_stdout_read_bytes = PHP_INT_MAX; $max_stderr_read_bytes = PHP_INT_MAX; if ($read_buffer_size !== null) { - $max_stdout_read_bytes = $read_buffer_size - strlen($this->stdout); - $max_stderr_read_bytes = $read_buffer_size - strlen($this->stderr); + $stdout_len = $this->getStdoutBufferLength(); + $stderr_len = $this->getStderrBufferLength(); + + $max_stdout_read_bytes = $read_buffer_size - $stdout_len; + $max_stderr_read_bytes = $read_buffer_size - $stderr_len; } if ($max_stdout_read_bytes > 0) { $this->stdout .= $this->readAndDiscard( $stdout, - $this->getStdoutSizeLimit() - strlen($this->stdout), + $this->getStdoutSizeLimit() - $this->getStdoutBufferLength(), 'stdout', $max_stdout_read_bytes); } @@ -772,7 +790,7 @@ if ($max_stderr_read_bytes > 0) { $this->stderr .= $this->readAndDiscard( $stderr, - $this->getStderrSizeLimit() - strlen($this->stderr), + $this->getStderrSizeLimit() - $this->getStderrBufferLength(), 'stderr', $max_stderr_read_bytes); } @@ -1013,5 +1031,20 @@ ); } + private function getStdoutBufferLength() { + if ($this->stdout === null) { + return 0; + } + + return strlen($this->stdout); + } + + private function getStderrBufferLength() { + if ($this->stderr === null) { + return 0; + } + + return strlen($this->stderr); + } } diff -Nru phabricator-0~git20200925/arcanist/src/future/exec/PhutilExecPassthru.php phabricator-0~git20220903/arcanist/src/future/exec/PhutilExecPassthru.php --- phabricator-0~git20200925/arcanist/src/future/exec/PhutilExecPassthru.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/exec/PhutilExecPassthru.php 2022-05-17 23:15:03.000000000 +0000 @@ -10,8 +10,8 @@ * This is primarily useful for executing things like `$EDITOR` from command * line scripts. * - * $exec = new PhutilExecPassthru('ls %s', $dir); - * $err = $exec->execute(); + * $exec = new PhutilExecPassthru('nano -- %s', $filename); + * $err = $exec->resolve(); * * You can set the current working directory for the command with * @{method:setCWD}, and set the environment with @{method:setEnv}. @@ -30,6 +30,14 @@ /* -( Executing Passthru Commands )---------------------------------------- */ + public function execute() { + phlog( + pht( + 'The "execute()" method of "PhutilExecPassthru" is deprecated and '. + 'calls should be replaced with "resolve()". See T13660.')); + return $this->resolve(); + } + /** * Execute this command. * @@ -37,7 +45,7 @@ * * @task command */ - public function execute() { + private function executeCommand() { $command = $this->getCommand(); $is_write = ($this->stdinData !== null); @@ -45,10 +53,14 @@ if ($is_write) { $stdin_spec = array('pipe', 'r'); } else { - $stdin_spec = STDIN; + $stdin_spec = PhutilSystem::getStdinHandle(); } - $spec = array($stdin_spec, STDOUT, STDERR); + $spec = array( + $stdin_spec, + PhutilSystem::getStdoutHandle(), + PhutilSystem::getStderrHandle(), + ); $pipes = array(); $unmasked_command = $command->getUnmaskedString(); @@ -116,7 +128,7 @@ // make it easier to share code with ExecFuture. if (!$this->hasResult()) { - $result = $this->execute(); + $result = $this->executeCommand(); $this->setResult($result); } diff -Nru phabricator-0~git20200925/arcanist/src/future/exec/PhutilExecutableFuture.php phabricator-0~git20220903/arcanist/src/future/exec/PhutilExecutableFuture.php --- phabricator-0~git20200925/arcanist/src/future/exec/PhutilExecutableFuture.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/exec/PhutilExecutableFuture.php 2022-05-17 23:15:03.000000000 +0000 @@ -19,7 +19,7 @@ pht( 'Command (of class "%s") was constructed with a '. '"PhutilCommandString", but also passed arguments. '. - 'When using a preprebuilt command, you must not pass '. + 'When using a prebuilt command, you must not pass '. 'arguments.', get_class($this))); } diff -Nru phabricator-0~git20200925/arcanist/src/future/exec/__tests__/ExecPassthruTestCase.php phabricator-0~git20220903/arcanist/src/future/exec/__tests__/ExecPassthruTestCase.php --- phabricator-0~git20200925/arcanist/src/future/exec/__tests__/ExecPassthruTestCase.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/exec/__tests__/ExecPassthruTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -11,7 +11,7 @@ $bin = $this->getSupportExecutable('exit'); $exec = new PhutilExecPassthru('php -f %R', $bin); - $err = $exec->execute(); + $err = $exec->resolve(); $this->assertEqual(0, $err); } diff -Nru phabricator-0~git20200925/arcanist/src/future/FutureIterator.php phabricator-0~git20220903/arcanist/src/future/FutureIterator.php --- phabricator-0~git20200925/arcanist/src/future/FutureIterator.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/FutureIterator.php 2022-05-17 23:15:03.000000000 +0000 @@ -194,7 +194,7 @@ * @task iterator */ public function next() { - // See T13572. If we preivously resolved and returned a Future, release + // See T13572. If we previously resolved and returned a Future, release // it now. This prevents us from holding Futures indefinitely when callers // like FuturePool build long-lived iterators and keep adding new Futures // to them. diff -Nru phabricator-0~git20200925/arcanist/src/future/http/BaseHTTPFuture.php phabricator-0~git20220903/arcanist/src/future/http/BaseHTTPFuture.php --- phabricator-0~git20200925/arcanist/src/future/http/BaseHTTPFuture.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/http/BaseHTTPFuture.php 2022-05-17 23:15:03.000000000 +0000 @@ -206,12 +206,14 @@ * @task config */ public function getHeaders($filter = null) { - $filter = strtolower($filter); + if ($filter !== null) { + $filter = phutil_utf8_strtolower($filter); + } $result = array(); foreach ($this->headers as $header) { list($name, $value) = $header; - if (!$filter || ($filter == strtolower($name))) { + if (($filter === null) || ($filter === phutil_utf8_strtolower($name))) { $result[] = $header; } } diff -Nru phabricator-0~git20200925/arcanist/src/future/http/HTTPSFuture.php phabricator-0~git20220903/arcanist/src/future/http/HTTPSFuture.php --- phabricator-0~git20200925/arcanist/src/future/http/HTTPSFuture.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/http/HTTPSFuture.php 2022-05-17 23:15:03.000000000 +0000 @@ -269,7 +269,7 @@ curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, $allowed_protocols); } - if (strlen($this->rawBody)) { + if ($this->rawBody !== null) { if ($this->getData()) { throw new Exception( pht( diff -Nru phabricator-0~git20200925/arcanist/src/future/MethodCallFuture.php phabricator-0~git20220903/arcanist/src/future/MethodCallFuture.php --- phabricator-0~git20200925/arcanist/src/future/MethodCallFuture.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/MethodCallFuture.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,36 @@ +callObject = $object; + $this->callMethod = $method; + $this->callArgv = array_slice($argv, 2); + } + + public function isReady() { + + $call = array($this->callObject, $this->callMethod); + $argv = $this->callArgv; + + $result = call_user_func_array($call, $argv); + $this->setResult($result); + + return true; + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/future/oauth/PhutilOAuth1Future.php phabricator-0~git20220903/arcanist/src/future/oauth/PhutilOAuth1Future.php --- phabricator-0~git20200925/arcanist/src/future/oauth/PhutilOAuth1Future.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/oauth/PhutilOAuth1Future.php 2022-05-17 23:15:03.000000000 +0000 @@ -268,7 +268,8 @@ throw new Exception(pht('%s failed!', 'openssl_sign()')); } - openssl_free_key($pkey); + // Deprecated in PHP 8; key is automatically freed. + @openssl_free_key($pkey); return base64_encode($signature); case 'PLAINTEXT': diff -Nru phabricator-0~git20200925/arcanist/src/future/__tests__/MethodCallFutureTestCase.php phabricator-0~git20220903/arcanist/src/future/__tests__/MethodCallFutureTestCase.php --- phabricator-0~git20200925/arcanist/src/future/__tests__/MethodCallFutureTestCase.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/future/__tests__/MethodCallFutureTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,57 @@ +resolve(); + + $this->assertEqual(6, $result, pht('MethodCallFuture: getSum(1, 2, 3)')); + + $future = new MethodCallFuture($this, 'getSum'); + $result = $future->resolve(); + + $this->assertEqual(0, $result, pht('MethodCallFuture: getSum()')); + } + + public function testMethodCallFutureExceptions() { + $future = new MethodCallFuture($this, 'raiseException'); + + // See T13666. Using "FutureIterator" to advance the future until it is + // ready to resolve should NOT throw an exception. + + foreach (new FutureIterator(array($future)) as $resolvable) { + // Continue below... + } + + $caught = null; + try { + $future->resolve(); + } catch (PhutilMethodNotImplementedException $ex) { + $caught = $ex; + } + + $this->assertTrue( + ($caught instanceof PhutilMethodNotImplementedException), + pht('MethodCallFuture: exceptions raise at resolution.')); + } + + public function getSum(/* ... */) { + $args = func_get_args(); + + $sum = 0; + foreach ($args as $arg) { + $sum += $arg; + } + + return $sum; + } + + public function raiseException() { + // We just want to throw any narrow exception so the test isn't catching + // too broad an exception type. This is simulating some exception during + // future resolution. + throw new PhutilMethodNotImplementedException(); + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/init/lib/moduleutils.php phabricator-0~git20220903/arcanist/src/init/lib/moduleutils.php --- phabricator-0~git20200925/arcanist/src/init/lib/moduleutils.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/init/lib/moduleutils.php 2022-05-17 23:15:03.000000000 +0000 @@ -36,18 +36,6 @@ return phutil_get_library_name_for_root($root); } -/** - * Warns about use of deprecated behavior. - */ -function phutil_deprecated($what, $why) { - PhutilErrorHandler::dispatchErrorMessage( - PhutilErrorHandler::DEPRECATED, - $what, - array( - 'why' => $why, - )); -} - function phutil_load_library($path) { PhutilBootloader::getInstance()->loadLibrary($path); } diff -Nru phabricator-0~git20200925/arcanist/src/init/lib/PhutilMissingSymbolException.php phabricator-0~git20220903/arcanist/src/init/lib/PhutilMissingSymbolException.php --- phabricator-0~git20200925/arcanist/src/init/lib/PhutilMissingSymbolException.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/init/lib/PhutilMissingSymbolException.php 2022-05-17 23:15:03.000000000 +0000 @@ -18,7 +18,7 @@ 'moved, your library map may need to be rebuilt. You can rebuild '. 'the map by running "arc liberate".'. "\n\n". - 'For more information, see: https://phurl.io/newclasses', + 'For more information, see: https://phurl.io/u/newclasses', $symbol, $type, $reason); diff -Nru phabricator-0~git20200925/arcanist/src/internationalization/pht.php phabricator-0~git20220903/arcanist/src/internationalization/pht.php --- phabricator-0~git20200925/arcanist/src/internationalization/pht.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/internationalization/pht.php 2022-05-17 23:15:03.000000000 +0000 @@ -44,3 +44,7 @@ function phutil_person(PhutilPerson $person) { return $person; } + +function pht_list(array $items) { + return implode(', ', $items); +} diff -Nru phabricator-0~git20200925/arcanist/src/land/engine/ArcanistGitLandEngine.php phabricator-0~git20220903/arcanist/src/land/engine/ArcanistGitLandEngine.php --- phabricator-0~git20200925/arcanist/src/land/engine/ArcanistGitLandEngine.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/land/engine/ArcanistGitLandEngine.php 2022-05-17 23:15:03.000000000 +0000 @@ -274,9 +274,11 @@ // as changes. list($changes) = $api->execxLocal( - 'diff --no-ext-diff %s..%s --', - $into_commit, - $max_hash); + 'diff --no-ext-diff %s --', + gitsprintf( + '%s..%s', + $into_commit, + $max_hash)); $changes = trim($changes); if (!strlen($changes)) { @@ -298,78 +300,186 @@ $api->getDisplayHash($max_hash), $max_commit->getDisplaySummary())); - $argv = array(); - $argv[] = '--no-stat'; - $argv[] = '--no-commit'; - - // When we're merging into the empty state, Git refuses to perform the - // merge until we tell it explicitly that we're doing something unusual. - if ($is_empty) { - $argv[] = '--allow-unrelated-histories'; - } - - if ($this->isSquashStrategy()) { - // NOTE: We're explicitly specifying "--ff" to override the presence - // of "merge.ff" options in user configuration. - $argv[] = '--ff'; - $argv[] = '--squash'; + // See T13576. We have several different approaches for performing the + // actual merge. + // + // In the simplest case, we're using the "merge" strategy. This means + // we always want to merge the entire history, and we can just use a + // "git merge" to accomplish our goal. No other approach is permissible + // here, so if that doesn't work we're all done and just tell the user + // to go resolve conflicts. + // + // If we're using the "squash" strategy, we may be merging a range of + // commits that aren't direct descendants of any ancestor of the state + // we're merging into. That is, there may be some ancestors of this + // range that we do NOT want to merge. A simple way to get into this + // state is to use "--pick". We need to slice off only the commits we + // want to merge to ensure we don't bring anything extra along. + // + // If history is simple and linear, we can select this slice with + // "git rebase". However, if history includes merge commits, it seems + // as though there are many cases where a (non-interactive) rebase is + // doomed to failure. + // + // If a "git rebase" fails, try to "reduce" the slice first, by using + // a "git merge --squash" to collapse the whole slice on top of its + // parent. This produces a single non-merge commit with all the changes, + // which we can then rebase and merge. + + $try = array(); + if ($this->isSquashStrategy() && !$is_empty) { + $try[] = 'rebase-merge'; + $try[] = 'reduce-rebase-merge'; } else { - $argv[] = '--no-ff'; + $try[] = 'merge'; } - $argv[] = '--'; + $merge_exceptions = array(); + $merge_complete = false; + foreach ($try as $approach) { + $reduce_min = null; + $reduce_max = null; - $is_rebasing = false; - $is_merging = false; - try { - if ($this->isSquashStrategy() && !$is_empty) { - // If we're performing a squash merge, we're going to rebase the - // commit range first. We only want to merge the specific commits - // in the range, and merging too much can create conflicts. + $rebase_min = null; + $rebase_max = null; - $api->execxLocal('checkout %s --', $max_hash); + $merge_hash = null; + $force_resolve = false; - $is_rebasing = true; - $api->execxLocal( - 'rebase --onto %s -- %s', - $into_commit, - $min_hash.'^'); - $is_rebasing = false; + switch ($approach) { + case 'reduce-rebase-merge': + $reduce_min = $min_hash; + $reduce_max = $max_hash; - $merge_hash = $api->getCanonicalRevisionName('HEAD'); - } else { - $merge_hash = $max_hash; + $log->writeStatus( + pht('MERGE'), + pht('Attempting to reduce and rebase changes.')); + break; + case 'rebase-merge': + $rebase_min = $min_hash; + $rebase_max = $max_hash; + + $log->writeStatus( + pht('MERGE'), + pht('Attempting to rebase changes.')); + break; + case 'merge': + $merge_hash = $max_hash; + + $log->writeStatus( + pht('MERGE'), + pht('Attempting to merge changes.')); + break; + default: + throw new Exception( + pht( + 'Unknown merge approach "%s".', + $approach)); } - $api->execxLocal('checkout %s --', $into_commit); + try { + if ($reduce_max) { + $reduce_dst = $reduce_min.'^'; + + // Squash the "into" state on top of the range. The goal is to + // guarantee that there are no unresolved conflicts between the + // maximum commit and the "into" state, because we're going to + // force conflicts to resolve in our favor later. + + $this->applyMergeOperation( + $into_commit, + $reduce_max, + true, + $is_empty); + + $join_hash = $this->applyCommitOperation( + sprintf( + 'arc land: join (%s -> %s)', + $api->getDisplayHash($into_commit), + $api->getDisplayHash($reduce_max)), + null, + null, + $allow_empty = true); + + // Squash the range, including the new merge, into a single + // commit. The goal here is to produce a new range with no merge + // commits so we can rebase it (we'll produce a sequence exactly + // one commit long). + + $this->applyMergeOperation( + $join_hash, + $reduce_dst, + true, + $is_empty); + + $reduce_hash = $this->applyCommitOperation( + sprintf( + 'arc land: reduce (%s..%s -> %s)', + $api->getDisplayHash($reduce_min), + $api->getDisplayHash($reduce_max), + $reduce_dst)); + + // We've reduced the range into a new range that is one commit + // long, has no merge commits, and has no conflicts against the + // "into" state. + + // We'll rebase it and force conflicts to resolve in favor of the + // reduced state. The hope is that we've taken sufficient steps to + // guarantee this resolution is always reasonable. + + $rebase_min = $reduce_hash; + $rebase_max = $reduce_hash; + $force_resolve = true; + } - $argv[] = $merge_hash; + if ($rebase_max) { + $merge_hash = $this->applyRebaseOperation( + $rebase_min, + $rebase_max, + $into_commit, + $force_resolve); + } - $is_merging = true; - $api->execxLocal('merge %Ls', $argv); - $is_merging = false; - } catch (CommandException $ex) { + $this->applyMergeOperation( + $merge_hash, + $into_commit, + $this->isSquashStrategy(), + $is_empty); + + $log->writeStatus(pht('DONE'), pht('Merge succeeded.')); + + $merge_complete = true; + } catch (CommandException $ex) { + $merge_exceptions[] = $ex; + } + + if ($merge_complete) { + break; + } + } + + if (!$merge_complete) { $direct_symbols = $max_commit->getDirectSymbols(); $indirect_symbols = $max_commit->getIndirectSymbols(); if ($direct_symbols) { $message = pht( 'Local commit "%s" (%s) does not merge cleanly into "%s". '. - 'Merge or rebase local changes so they can merge cleanly.', + 'Rebase or merge local changes so they can merge cleanly.', $api->getDisplayHash($max_hash), $this->getDisplaySymbols($direct_symbols), $api->getDisplayHash($into_commit)); } else if ($indirect_symbols) { $message = pht( 'Local commit "%s" (reachable from: %s) does not merge cleanly '. - 'into "%s". Merge or rebase local changes so they can merge '. + 'into "%s". Rebase or merge local changes so they can merge '. 'cleanly.', $api->getDisplayHash($max_hash), $this->getDisplaySymbols($indirect_symbols), $api->getDisplayHash($into_commit)); } else { $message = pht( - 'Local commit "%s" does not merge cleanly into "%s". Merge or '. - 'rebase local changes so they can merge cleanly.', + 'Local commit "%s" does not merge cleanly into "%s". Rebase or '. + 'merge local changes so they can merge cleanly.', $api->getDisplayHash($max_hash), $api->getDisplayHash($into_commit)); } @@ -386,18 +496,6 @@ 'Use "--incremental" to merge and push changes one by one.')); } - if ($is_rebasing) { - $api->execManualLocal('rebase --abort'); - } - - if ($is_merging) { - $api->execManualLocal('merge --abort'); - } - - if ($is_merging || $is_rebasing) { - $api->execManualLocal('reset --hard HEAD --'); - } - throw new PhutilArgumentUsageException( pht('Encountered a merge conflict.')); } @@ -408,15 +506,10 @@ $revision_ref = $set->getRevisionRef(); $commit_message = $revision_ref->getCommitMessage(); - $future = $api->execFutureLocal( - 'commit --author %s --date %s -F - --', + $new_cursor = $this->applyCommitOperation( + $commit_message, $original_author, $original_date); - $future->write($commit_message); - $future->resolvex(); - - list($stdout) = $api->execxLocal('rev-parse --verify %s', 'HEAD'); - $new_cursor = trim($stdout); if ($is_empty) { // See T12876. If we're landing into the empty state, we just did a fake @@ -762,7 +855,7 @@ $api = $this->getRepositoryAPI(); list($stdout) = $api->execxLocal( - 'merge-base %s %s', + 'merge-base -- %s %s', $branch, $commit); $merge_base = trim($stdout); @@ -781,7 +874,7 @@ list($info) = $api->execxLocal( 'log -n1 --format=%s %s --', '%aD%n%an%n%ae', - $commit); + gitsprintf('%s', $commit)); $info = trim($info); list($date, $author, $email) = explode("\n", $info, 3); @@ -1452,19 +1545,19 @@ $commit_map = array(); foreach ($symbols as $symbol) { $symbol_commit = $symbol->getCommit(); - $format = '%H%x00%P%x00%s%x00'; + $format = '--format=%H%x00%P%x00%s%x00'; if ($into_commit === null) { list($commits) = $api->execxLocal( - 'log %s --format=%s', - $symbol_commit, - $format); + 'log %s %s --', + $format, + gitsprintf('%s', $symbol_commit)); } else { list($commits) = $api->execxLocal( - 'log %s --not %s --format=%s', - $symbol_commit, - $into_commit, - $format); + 'log %s %s --not %s --', + $format, + gitsprintf('%s', $symbol_commit), + gitsprintf('%s', $into_commit)); } $commits = phutil_split_lines($commits, false); @@ -1599,4 +1692,114 @@ 'Desired merge strategy is ambiguous, choose an explicit strategy.')); } + private function applyRebaseOperation( + $src_min, + $src_max, + $dst, + $force_resolve) { + + $api = $this->getRepositoryAPI(); + + $api->execxLocal('checkout %s --', $src_max); + + $argv = array(); + $argv[] = '--onto'; + $argv[] = gitsprintf('%s', $dst); + + if ($force_resolve) { + $argv[] = '--strategy'; + $argv[] = 'recursive'; + $argv[] = '--strategy-option'; + $argv[] = 'theirs'; + } + + $argv[] = '--'; + $argv[] = gitsprintf('%s', $src_min.'^'); + + try { + $api->execxLocal('rebase %Ls', $argv); + } catch (CommandException $ex) { + $api->execManualLocal('rebase --abort'); + $api->execManualLocal('reset --hard HEAD --'); + throw $ex; + } + + $merge_hash = $api->getCanonicalRevisionName('HEAD'); + + return $merge_hash; + } + + private function applyMergeOperation($src, $dst, $is_squash, $is_empty) { + $api = $this->getRepositoryAPI(); + + $api->execxLocal('checkout %s --', $dst); + + $argv = array(); + $argv[] = '--no-stat'; + $argv[] = '--no-commit'; + + // When we're merging into the empty state, Git refuses to perform the + // merge until we tell it explicitly that we're doing something unusual. + if ($is_empty) { + $argv[] = '--allow-unrelated-histories'; + } + + if ($is_squash) { + // NOTE: We're explicitly specifying "--ff" to override the presence + // of "merge.ff" options in user configuration. + $argv[] = '--ff'; + $argv[] = '--squash'; + } else { + $argv[] = '--no-ff'; + } + + $argv[] = '--'; + + $argv[] = $src; + + try { + $api->execxLocal('merge %Ls', $argv); + } catch (CommandException $ex) { + $api->execManualLocal('merge --abort'); + $api->execManualLocal('reset --hard HEAD'); + throw $ex; + } + } + + private function applyCommitOperation( + $message, + $author = null, + $date = null, + $allow_empty = false) { + + $api = $this->getRepositoryAPI(); + + $argv = array(); + if ($author !== null) { + $argv[] = '--author'; + $argv[] = $author; + } + + if ($date !== null) { + $argv[] = '--date'; + $argv[] = $date; + } + + if ($allow_empty) { + $argv[] = '--allow-empty'; + } + + $future = $api->execFutureLocal( + 'commit %Ls -F - --', + $argv); + $future->write($message); + $future->resolvex(); + + list($stdout) = $api->execxLocal('rev-parse --verify %s', 'HEAD'); + $new_commit = trim($stdout); + + return $new_commit; + } + + } diff -Nru phabricator-0~git20200925/arcanist/src/land/engine/ArcanistLandEngine.php phabricator-0~git20220903/arcanist/src/land/engine/ArcanistLandEngine.php --- phabricator-0~git20200925/arcanist/src/land/engine/ArcanistLandEngine.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/land/engine/ArcanistLandEngine.php 2022-05-17 23:15:03.000000000 +0000 @@ -780,13 +780,15 @@ $display_summary = $commit->getDisplaySummary(); if ($is_implicit) { + // NOTE: Mark commits with both a color and a character so the marking + // survives copy/paste. echo tsprintf( - " %s %s\n", + " ! %s %s\n", $display_hash, $display_summary); } else { echo tsprintf( - " %s %s\n", + " %s %s\n", $display_hash, $display_summary); } @@ -1405,6 +1407,21 @@ ArcanistLandCommitSet $set, $into_commit); abstract protected function pushChange($into_commit); + + /** + * Update all local refs that depend on refs selected-and-modified during the + * land. E.g. with branches named change1 -> change2 -> change3 and using + * `arc land change2`, in the general case the local change3 should be + * rebased onto the landed version of change2 so that it no longer has + * out-of-date ancestors. + * + * When multiple revisions are landed at once this will be called in a loop + * for each set, in order of max to min, where max is the latest descendant + * and min is the earliest ancestor. This is done so that non-landing commits + * that are descendants of the latest revision will only be rebased once. + * + * @param ArcanistLandCommitSet The current commit set to cascade. + */ abstract protected function cascadeState( ArcanistLandCommitSet $set, $into_commit); @@ -1413,12 +1430,35 @@ return ($this->getStrategy() === 'squash'); } + /** + * Prunes the given sets of commits. This should be called after the sets + * have been merged. + * + * @param array The list of ArcanistLandCommitSet to prune, in order of + * min to max commit set, where min is the earliest ancestor and max + * is the latest descendant. + */ abstract protected function pruneBranches(array $sets); + /** + * Restore the local repository to an expected state after landing. This + * should only be called after all changes have been merged, pruned, and + * pushed. + * + * @param string The commit hash that was landed into. + * @param ArcanistRepositoryLocalState The local state that was captured + * at the beginning of the land process. This may include stashed changes. + */ abstract protected function reconcileLocalState( $into_commit, ArcanistRepositoryLocalState $state); + /** + * Display information to the user about how to proceed since the land + * process was not fully completed. The merged branch has not been pushed. + * + * @param string The commit hash that was landed into. + */ abstract protected function didHoldChanges($into_commit); private function selectMergeStrategy() { diff -Nru phabricator-0~git20200925/arcanist/src/land/engine/ArcanistMercurialLandEngine.php phabricator-0~git20220903/arcanist/src/land/engine/ArcanistMercurialLandEngine.php --- phabricator-0~git20200925/arcanist/src/land/engine/ArcanistMercurialLandEngine.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/land/engine/ArcanistMercurialLandEngine.php 2022-05-17 23:15:03.000000000 +0000 @@ -6,6 +6,8 @@ private $ontoBranchMarker; private $ontoMarkers; + private $rebasedActiveCommit; + protected function getDefaultSymbols() { $api = $this->getRepositoryAPI(); $log = $this->getLogEngine(); @@ -698,8 +700,14 @@ $commit_map = array(); foreach ($symbols as $symbol) { $symbol_commit = $symbol->getCommit(); - $template = '{node}-{parents}-'; + $template = '{node}-{parents % \'{node} \'}-{desc|firstline}\\n'; + // The returned array of commits is expected to be ordered by max to min + // where the max commit has no descendants in the range and the min + // commit has no ancestors in the range. Use 'reverse()' in the template + // so the output is ordered with the max commit as the first line. The + // max/min terms are used in a topological sense as chronological terms + // for commits may be misleading or incorrect in some situations. if ($into_commit === null) { list($commits) = $api->execxLocal( 'log --rev %s --template %s --', @@ -789,8 +797,14 @@ $commits = $set->getCommits(); - $min_commit = last($commits)->getHash(); - $max_commit = head($commits)->getHash(); + // confirmCommits() reverses the order of the commits as they're ordered + // above in selectCommits(). Now the head of the list is the min commit and + // the last is the max commit, where within the range the max commit has no + // descendants and the min commit has no ancestors. The min/max terms are + // used in a topological sense as chronological terms for commits can be + // misleading or incorrect in certain situations. + $min_commit = head($commits)->getHash(); + $max_commit = last($commits)->getHash(); $revision_ref = $set->getRevisionRef(); $commit_message = $revision_ref->getCommitMessage(); @@ -820,13 +834,19 @@ $argv[] = '--keep'; $argv[] = '--collapse'; - $future = $api->execFutureLocal('rebase %Ls', $argv); + $future = $api->execFutureLocalWithExtension( + 'rebase', + 'rebase %Ls', + $argv); $future->write($commit_message); $future->resolvex(); } catch (CommandException $ex) { - // TODO - // $api->execManualLocal('rebase --abort'); + // Aborting the rebase should restore the same state prior to running the + // rebase command. + $api->execManualLocalWithExtension( + 'rebase', + 'rebase --abort'); throw $ex; } @@ -855,13 +875,21 @@ list($stdout) = $api->execxLocal('log --rev tip --template %s', '{node}'); $new_cursor = trim($stdout); + // If any of the commits that were rebased was the active commit before the + // workflow started, track the new commit so it can be used as the working + // directory after the land has succeeded. + if (isset($obsolete_map[$this->getLocalState()->getLocalCommit()])) { + $this->rebasedActiveCommit = $new_cursor; + } + return $new_cursor; } protected function pushChange($into_commit) { $api = $this->getRepositoryAPI(); - list($head, $body, $tail) = $this->newPushCommands($into_commit); + list($head, $body, $tail_pass, $tail_fail) = $this->newPushCommands( + $into_commit); foreach ($head as $command) { $api->execxLocal('%Ls', $command); @@ -876,10 +904,20 @@ 'Push failed! Fix the error and run "arc land" again.')); } } - } finally { - foreach ($tail as $command) { + + foreach ($tail_pass as $command) { $api->execxLocal('%Ls', $command); } + } catch (Exception $ex) { + foreach ($tail_fail as $command) { + $api->execxLocal('%Ls', $command); + } + throw $ex; + } catch (Throwable $ex) { + foreach ($tail_fail as $command) { + $api->execxLocal('%Ls', $command); + } + throw $ex; } } @@ -888,7 +926,8 @@ $head_commands = array(); $body_commands = array(); - $tail_commands = array(); + $tail_pass_commands = array(); + $tail_fail_commands = array(); $bookmarks = array(); foreach ($this->ontoMarkers as $onto_marker) { @@ -902,7 +941,7 @@ // to the merge commit. (There doesn't seem to be any way to specify // "push commit X as bookmark Y" in Mercurial.) - $restore = array(); + $restore_bookmarks = array(); if ($bookmarks) { $markers = $api->newMarkerRefQuery() ->withNames(mpull($bookmarks, 'getName')) @@ -934,7 +973,9 @@ hgsprintf('%s', $new_position), $bookmark_name); - $restore[$bookmark_name] = $old_position; + if ($old_position !== null) { + $restore_bookmarks[$bookmark_name] = $old_position; + } } } @@ -963,28 +1004,41 @@ // Finally, restore the bookmarks. - foreach ($restore as $bookmark_name => $old_position) { - $tail = array(); - $tail[] = 'bookmark'; - - if ($old_position === null) { - $tail[] = '--delete'; - } else { - $tail[] = '--force'; - $tail[] = '--rev'; - $tail[] = hgsprintf('%s', $api->getDisplayHash($old_position)); + if ($restore_bookmarks) { + // Instead of restoring the previous state, assume landing onto bookmarks + // also updates those bookmarks in the remote. After pushing, pull the + // latest state of these bookmarks. Mercurial allows pulling multiple + // bookmarks in a single pull command which will be faster than pulling + // them from a remote individually. + $tail = array( + 'pull', + ); + + foreach ($restore_bookmarks as $bookmark_name => $old_position) { + $tail[] = '--bookmark'; + $tail[] = $bookmark_name; + + // In the failure case restore the state of the bookmark. Mercurial + // does not provide a way to move multiple bookmarks in a single + // command however these commands do not involve the remote. + $tail_fail_commands[] = array( + 'bookmark', + '--force', + '--rev', + hgsprintf('%s', $api->getDisplayHash($old_position)), + ); } - $tail[] = '--'; - $tail[] = $bookmark_name; - - $tail_commands[] = $tail; + if ($tail) { + $tail_pass_commands[] = $tail; + } } return array( $head_commands, $body_commands, - $tail_commands, + $tail_pass_commands, + $tail_fail_commands, ); } @@ -1015,12 +1069,17 @@ // be deleted, we can skip this rebase? try { - $api->execxLocal( + $api->execxLocalWithExtension( + 'rebase', 'rebase --source %s --dest %s --keep --keepbranches', $child_hash, $new_commit); } catch (CommandException $ex) { - // TODO: Recover state. + // Aborting the rebase should restore the same state prior to running + // the rebase command. + $api->execManualLocalWithExtension( + 'rebase', + 'rebase --abort'); throw $ex; } } @@ -1040,6 +1099,8 @@ $revs = array(); $obsolete_map = array(); + $using_evolve = $api->getMercurialFeature('evolve'); + // We've rebased all descendants already, so we can safely delete all // of these commits. @@ -1047,10 +1108,22 @@ foreach ($sets as $set) { $commits = $set->getCommits(); + // In the commit set the min commit should be the commit with no + // ancestors and the max commit should be the commit with no descendants. + // The min/max terms are used in a toplogical sense as chronological + // terms for commits may be misleading or incorrect in some situations. $min_commit = head($commits)->getHash(); $max_commit = last($commits)->getHash(); - $revs[] = hgsprintf('%s::%s', $min_commit, $max_commit); + if ($using_evolve) { + // If non-head series of commits are rebased while the evolve extension + // is in use, the rebase leaves behind the entire series of descendants + // in which case the entire chain needs removed, not just a section. + // Otherwise this results in the prune leaving behind orphaned commits. + $revs[] = hgsprintf('%s::', $min_commit); + } else { + $revs[] = hgsprintf('%s::%s', $min_commit, $max_commit); + } foreach ($commits as $commit) { $obsolete_map[$commit->getHash()] = true; @@ -1071,10 +1144,7 @@ // bookmarks which point at these now-obsoleted commits. $bookmark_refs = $api->newMarkerRefQuery() - ->withMarkerTypes( - array( - ArcanistMarkerRef::TYPE_BOOKMARK, - )) + ->withMarkerTypes(array(ArcanistMarkerRef::TYPE_BOOKMARK)) ->execute(); foreach ($bookmark_refs as $bookmark_ref) { $bookmark_hash = $bookmark_ref->getCommitHash(); @@ -1093,13 +1163,14 @@ $bookmark_name); } - if ($api->getMercurialFeature('evolve')) { + if ($using_evolve) { $api->execxLocal( 'prune --rev %s', $rev_set); } else { - $api->execxLocal( - '--config extensions.strip= strip --rev %s', + $api->execxLocalWithExtension( + 'strip', + 'strip --rev %s', $rev_set); } } @@ -1108,7 +1179,54 @@ $into_commit, ArcanistRepositoryLocalState $state) { - // TODO: For now, just leave users wherever they ended up. + $api = $this->getRepositoryAPI(); + + // If the starting working state was not part of land process just update + // to that original working state. + if ($this->rebasedActiveCommit === null) { + $update_marker = $this->getLocalState()->getLocalCommit(); + if ($this->getLocalState()->getLocalBookmark() !== null) { + $update_marker = $this->getLocalState()->getLocalBookmark(); + } + + $api->execxLocal( + 'update -- %s', + $update_marker); + + $state->discardLocalState(); + return; + } + + // If the working state was landed into multiple destinations then the + // resulting working state is ambiguous. + if (count($this->ontoMarkers) != 1) { + $state->discardLocalState(); + return; + } + + // Get the current state of bookmarks + $bookmark_refs = $api->newMarkerRefQuery() + ->withMarkerTypes(array(ArcanistMarkerRef::TYPE_BOOKMARK)) + ->execute(); + + $update_marker = $this->rebasedActiveCommit; + + // Find any bookmarks which exist on the commit which is the result of the + // starting working directory's rebase. If any of those bookmarks are also + // the destination marker then we use that bookmark as the update in order + // for it to become active. + $onto_marker = $this->ontoMarkers[0]->getName(); + foreach ($bookmark_refs as $bookmark_ref) { + if ($bookmark_ref->getCommitHash() == $this->rebasedActiveCommit && + $bookmark_ref->getName() == $onto_marker) { + $update_marker = $onto_marker; + break; + } + } + + $api->execxLocal( + 'update -- %s', + $update_marker); $state->discardLocalState(); } @@ -1120,8 +1238,9 @@ $message = pht( 'Holding changes locally, they have not been pushed.'); - list($head, $body, $tail) = $this->newPushCommands($into_commit); - $commands = array_merge($head, $body, $tail); + list($head, $body, $tail_pass, $tail_fail) = $this->newPushCommands( + $into_commit); + $commands = array_merge($head, $body, $tail_pass); echo tsprintf( "\n%!\n%s\n\n", diff -Nru phabricator-0~git20200925/arcanist/src/lint/engine/ArcanistLintEngine.php phabricator-0~git20220903/arcanist/src/lint/engine/ArcanistLintEngine.php --- phabricator-0~git20200925/arcanist/src/lint/engine/ArcanistLintEngine.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/engine/ArcanistLintEngine.php 2022-05-17 23:15:03.000000000 +0000 @@ -274,7 +274,7 @@ return ArcanistLintSeverity::isAtLeastAsSevere($severity, $minimum); } - final private function shouldUseCache( + private function shouldUseCache( $cache_granularity, $repository_version) { @@ -313,7 +313,7 @@ return $this; } - final private function isRelevantMessage(ArcanistLintMessage $message) { + private function isRelevantMessage(ArcanistLintMessage $message) { // When a user runs "arc lint", we default to raising only warnings on // lines they have changed (errors are still raised anywhere in the // file). The list of $changed lines may be null, to indicate that the diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistCSharpLinter.php phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistCSharpLinter.php --- phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistCSharpLinter.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistCSharpLinter.php 2022-05-17 23:15:03.000000000 +0000 @@ -64,11 +64,11 @@ throw new Exception( pht( "In order to keep StyleCop integration with IDEs and other tools ". - "consistent with Arcanist results, you aren't permitted to ". + "consistent with lint results, you aren't permitted to ". "disable StyleCop rules within '%s'. Instead configure the ". "severity using the StyleCop settings dialog (usually accessible ". "from within your IDE). StyleCop settings for your project will ". - "be used when linting for Arcanist.", + "be used when linting.", '.arclint')); } } @@ -132,8 +132,8 @@ } else if ($ver > self::SUPPORTED_VERSION) { throw new Exception( pht( - 'Arcanist does not support this version of %s (it is newer). '. - 'You can try upgrading Arcanist with `%s`.', + 'This version of %s is not supported (it is too new). '. + 'You can try upgrading with `%s`.', 'cslint', 'arc upgrade')); } diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistGoLintLinter.php phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistGoLintLinter.php --- phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistGoLintLinter.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistGoLintLinter.php 2022-05-17 23:15:03.000000000 +0000 @@ -29,7 +29,7 @@ public function getInstallInstructions() { return pht( 'Install Golint using `%s`.', - 'go get github.com/golang/lint/golint'); + 'go get -u golang.org/x/lint/golint'); } public function shouldExpectCommandErrors() { diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistLinter.php phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistLinter.php --- phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistLinter.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistLinter.php 2022-05-17 23:15:03.000000000 +0000 @@ -291,7 +291,7 @@ * @param list * @return list */ - final private function filterPaths(array $paths) { + private function filterPaths(array $paths) { $engine = $this->getEngine(); $keep = array(); diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistPhutilLibraryLinter.php phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistPhutilLibraryLinter.php --- phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistPhutilLibraryLinter.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistPhutilLibraryLinter.php 2022-05-17 23:15:03.000000000 +0000 @@ -13,6 +13,7 @@ const LINT_UNKNOWN_SYMBOL = 1; const LINT_DUPLICATE_SYMBOL = 2; const LINT_ONE_CLASS_PER_FILE = 3; + const LINT_NONCANONICAL_SYMBOL = 4; public function getInfoName() { return pht('Phutil Library Linter'); @@ -43,6 +44,7 @@ self::LINT_UNKNOWN_SYMBOL => pht('Unknown Symbol'), self::LINT_DUPLICATE_SYMBOL => pht('Duplicate Symbol'), self::LINT_ONE_CLASS_PER_FILE => pht('One Class Per File'), + self::LINT_NONCANONICAL_SYMBOL => pht('Noncanonical Symbol'), ); } @@ -51,6 +53,14 @@ } public function willLintPaths(array $paths) { + + $libtype_map = array( + 'class' => 'class', + 'function' => 'function', + 'interface' => 'class', + 'class/interface' => 'class', + ); + // NOTE: For now, we completely ignore paths and just lint every library in // its entirety. This is simpler and relatively fast because we don't do any // detailed checks and all the data we need for this comes out of module @@ -59,6 +69,26 @@ $bootloader = PhutilBootloader::getInstance(); $libraries = $bootloader->getAllLibraries(); + // Load all the builtin symbols first. + $builtin_map = PhutilLibraryMapBuilder::newBuiltinMap(); + $builtin_map = $builtin_map['have']; + + $normal_symbols = array(); + $all_symbols = array(); + foreach ($builtin_map as $type => $builtin_symbols) { + $libtype = $libtype_map[$type]; + foreach ($builtin_symbols as $builtin_symbol => $ignored) { + $normal_symbol = $this->normalizeSymbol($builtin_symbol); + $normal_symbols[$type][$normal_symbol] = $builtin_symbol; + + $all_symbols[$libtype][$builtin_symbol] = array( + 'library' => null, + 'file' => null, + 'offset' => null, + ); + } + } + // Load the up-to-date map for each library, without loading the library // itself. This means lint results will accurately reflect the state of // the working copy. @@ -78,7 +108,6 @@ } } - $all_symbols = array(); foreach ($symbols as $library => $map) { // Check for files which declare more than one class/interface in the same // file, or mix function definitions with class/interface definitions. We @@ -124,13 +153,20 @@ } // Check for duplicate symbols: two files providing the same class or - // function. + // function. While doing this, we also build a map of normalized symbol + // names to original symbol names: we want a definition of "idx()" to + // collide with a definition of "IdX()", and want to perform spelling + // corrections later. + foreach ($map as $file => $spec) { $have = idx($spec, 'have', array()); foreach (array('class', 'function', 'interface') as $type) { - $libtype = ($type == 'interface') ? 'class' : $type; + $libtype = $libtype_map[$type]; foreach (idx($have, $type, array()) as $symbol => $offset) { - if (empty($all_symbols[$libtype][$symbol])) { + $normal_symbol = $this->normalizeSymbol($symbol); + + if (empty($normal_symbols[$libtype][$normal_symbol])) { + $normal_symbols[$libtype][$normal_symbol] = $symbol; $all_symbols[$libtype][$symbol] = array( 'library' => $library, 'file' => $file, @@ -139,23 +175,41 @@ continue; } - $osrc = $all_symbols[$libtype][$symbol]['file']; - $olib = $all_symbols[$libtype][$symbol]['library']; + $old_symbol = $normal_symbols[$libtype][$normal_symbol]; + $old_src = $all_symbols[$libtype][$old_symbol]['file']; + $old_lib = $all_symbols[$libtype][$old_symbol]['library']; + + // If these values are "null", it means that the symbol is a + // builtin symbol provided by PHP or a PHP extension. + + if ($old_lib === null) { + $message = pht( + 'Definition of symbol "%s" (of type "%s") in file "%s" in '. + 'library "%s" duplicates builtin definition of the same '. + 'symbol.', + $symbol, + $type, + $file, + $library); + } else { + $message = pht( + 'Definition of symbol "%s" (of type "%s") in file "%s" in '. + 'library "%s" duplicates prior definition in file "%s" in '. + 'library "%s".', + $symbol, + $type, + $file, + $library, + $old_src, + $old_lib); + } $this->raiseLintInLibrary( $library, $file, $offset, self::LINT_DUPLICATE_SYMBOL, - pht( - "Definition of %s '%s' in '%s' in library '%s' duplicates ". - "prior definition in '%s' in library '%s'.", - $type, - $symbol, - $file, - $library, - $osrc, - $olib)); + $message); } } } @@ -169,61 +223,150 @@ foreach ($map as $file => $spec) { $need = idx($spec, 'need', array()); foreach ($types as $type) { - $libtype = $type; - if ($type == 'interface' || $type == 'class/interface') { - $libtype = 'class'; - } + $libtype = $libtype_map[$type]; foreach (idx($need, $type, array()) as $symbol => $offset) { if (!empty($all_symbols[$libtype][$symbol])) { // Symbol is defined somewhere. continue; } - $libphutil_root = dirname(phutil_get_library_root('arcanist')); + $normal_symbol = $this->normalizeSymbol($symbol); + if (!empty($normal_symbols[$libtype][$normal_symbol])) { + $proper_symbol = $normal_symbols[$libtype][$normal_symbol]; + + switch ($type) { + case 'class': + $summary = pht( + 'Class symbol "%s" should be written as "%s".', + $symbol, + $proper_symbol); + break; + case 'function': + $summary = pht( + 'Function symbol "%s" should be written as "%s".', + $symbol, + $proper_symbol); + break; + case 'interface': + $summary = pht( + 'Interface symbol "%s" should be written as "%s".', + $symbol, + $proper_symbol); + break; + case 'class/interface': + $summary = pht( + 'Class or interface symbol "%s" should be written as "%s".', + $symbol, + $proper_symbol); + break; + default: + throw new Exception( + pht('Unknown symbol type "%s".', $type)); + } + + $this->raiseLintInLibrary( + $library, + $file, + $offset, + self::LINT_NONCANONICAL_SYMBOL, + $summary, + $symbol, + $proper_symbol); + + continue; + } + + $arcanist_root = dirname(phutil_get_library_root('arcanist')); + + switch ($type) { + case 'class': + $summary = pht( + 'Use of unknown class symbol "%s".', + $symbol); + break; + case 'function': + $summary = pht( + 'Use of unknown function symbol "%s".', + $symbol); + break; + case 'interface': + $summary = pht( + 'Use of unknown interface symbol "%s".', + $symbol); + break; + case 'class/interface': + $summary = pht( + 'Use of unknown class or interface symbol "%s".', + $symbol); + break; + } + + $details = pht( + "Common causes are:\n". + "\n". + " - Your copy of %s is out of date.\n". + " This is the most common cause.\n". + " Update this copy of %s:\n". + "\n". + " %s\n". + "\n". + " - Some other library is out of date.\n". + " Update the library this symbol appears in.\n". + "\n". + " - The symbol is misspelled.\n". + " Spell the symbol name correctly.\n". + "\n". + " - You added the symbol recently, but have not updated\n". + " the symbol map for the library.\n". + " Run \"arc liberate\" in the library where the symbol is\n". + " defined.\n". + "\n". + " - This symbol is defined in an external library.\n". + " Use \"@phutil-external-symbol\" to annotate it.\n". + " Use \"grep\" to find examples of usage.", + PlatformSymbols::getPlatformClientName(), + PlatformSymbols::getPlatformClientName(), + $arcanist_root); + + $message = implode( + "\n\n", + array( + $summary, + $details, + )); $this->raiseLintInLibrary( $library, $file, $offset, self::LINT_UNKNOWN_SYMBOL, - pht( - "Use of unknown %s '%s'. Common causes are:\n\n". - " - Your %s is out of date.\n". - " This is the most common cause.\n". - " Update this copy of libphutil: %s\n\n". - " - Some other library is out of date.\n". - " Update the library this symbol appears in.\n\n". - " - This symbol is misspelled.\n". - " Spell the symbol name correctly.\n". - " Symbol name spelling is case-sensitive.\n\n". - " - This symbol was added recently.\n". - " Run `%s` on the library it was added to.\n\n". - " - This symbol is external. Use `%s`.\n". - " Use `%s` to find usage examples of this directive.\n\n". - "*** ALTHOUGH USUALLY EASY TO FIX, THIS IS A SERIOUS ERROR.\n". - "*** THIS ERROR IS YOUR FAULT. YOU MUST RESOLVE IT.", - $type, - $symbol, - 'libphutil/', - $libphutil_root, - 'arc liberate', - '@phutil-external-symbol', - 'grep')); + $message); } } } } } - private function raiseLintInLibrary($library, $path, $offset, $code, $desc) { + private function raiseLintInLibrary( + $library, + $path, + $offset, + $code, + $desc, + $original = null, + $replacement = null) { $root = phutil_get_library_root($library); $this->activePath = $root.'/'.$path; - $this->raiseLintAtOffset($offset, $code, $desc); + $this->raiseLintAtOffset($offset, $code, $desc, $original, $replacement); } public function lintPath($path) { return; } + private function normalizeSymbol($symbol) { + return phutil_utf8_strtolower($symbol); + } + } diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistPyFlakesLinter.php phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistPyFlakesLinter.php --- phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistPyFlakesLinter.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistPyFlakesLinter.php 2022-05-17 23:15:03.000000000 +0000 @@ -35,7 +35,8 @@ list($stdout) = execx('%C --version', $this->getExecutableCommand()); $matches = array(); - if (preg_match('/^(?P\d+\.\d+\.\d+)$/', $stdout, $matches)) { + $pattern = '/^(?P\d+\.\d+\.\d+)( Python.*)?$/'; + if (preg_match($pattern, $stdout, $matches)) { return $matches['version']; } else { return false; @@ -52,7 +53,8 @@ $messages = array(); foreach ($lines as $line) { $matches = null; - if (!preg_match('/^(.*?):(\d+): (.*)$/', $line, $matches)) { + $pattern = '/^(?.*?):(?\d+):(?\d*) (?.*)$/'; + if (!preg_match($pattern, $line, $matches)) { continue; } foreach ($matches as $key => $match) { @@ -60,7 +62,7 @@ } $severity = ArcanistLintSeverity::SEVERITY_WARNING; - $description = $matches[3]; + $description = $matches['message']; $error_regexp = '/(^undefined|^duplicate|before assignment$)/'; if (preg_match($error_regexp, $description)) { @@ -69,7 +71,10 @@ $message = new ArcanistLintMessage(); $message->setPath($path); - $message->setLine($matches[2]); + $message->setLine($matches['line']); + if ($matches['column'] != '') { + $message->setChar($matches['column']); + } $message->setCode($this->getLinterName()); $message->setName($this->getLinterName()); $message->setDescription($description); diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistXMLLinter.php phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistXMLLinter.php --- phabricator-0~git20200925/arcanist/src/lint/linter/ArcanistXMLLinter.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/ArcanistXMLLinter.php 2022-05-17 23:15:03.000000000 +0000 @@ -27,7 +27,11 @@ } public function getCacheVersion() { - return LIBXML_VERSION; + if (defined('LIBXML_VERSION')) { + return LIBXML_VERSION; + } else { + return 'unavailable'; + } } public function lintPath($path) { diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/ArcanistLinterTestCase.php phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/ArcanistLinterTestCase.php --- phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/ArcanistLinterTestCase.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/ArcanistLinterTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -51,6 +51,13 @@ private function lintFile($file, ArcanistLinter $linter) { $linter = clone $linter; + if (!$linter->canRun()) { + $this->assertSkipped( + pht( + 'Linter "%s" can not run.', + get_class($linter))); + } + $contents = Filesystem::readFile($file); $contents = preg_split('/^~{4,}\n/m', $contents); if (count($contents) < 2) { @@ -283,9 +290,12 @@ } private function compareTransform($expected, $actual) { + $expected = phutil_string_cast($expected); + if (!strlen($expected)) { return; } + $this->assertEqual( $expected, $actual, diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/jshint/expected-conditional.lint-test phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/jshint/expected-conditional.lint-test --- phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/jshint/expected-conditional.lint-test 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/jshint/expected-conditional.lint-test 2022-05-17 23:15:03.000000000 +0000 @@ -3,4 +3,4 @@ return true; } ~~~~~~~~~~ -warning:2:16:W084 +warning:2:9:W084 diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/pyflakes/pyflakes.lint-test phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/pyflakes/pyflakes.lint-test --- phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/pyflakes/pyflakes.lint-test 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/pyflakes/pyflakes.lint-test 2022-05-17 23:15:03.000000000 +0000 @@ -2,6 +2,6 @@ x += 1 ~~~~~~~~~~ -warning:1:0 -warning:1:0 -error:3:0 +warning:1: +warning:1: +error:3: diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/rubocop/convention.lint-test phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/rubocop/convention.lint-test --- phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/rubocop/convention.lint-test 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/rubocop/convention.lint-test 2022-05-17 23:15:03.000000000 +0000 @@ -1,4 +1,6 @@ def hello() end ~~~~~~~~~~ -warning:1:10:- +warning:1:1 +warning:1:1 +warning:1:10 diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/rubocop/no_errors.lint-test phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/rubocop/no_errors.lint-test --- phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/rubocop/no_errors.lint-test 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/rubocop/no_errors.lint-test 2022-05-17 23:15:03.000000000 +0000 @@ -1,3 +1,5 @@ +# frozen_string_literal: true + def hello puts 'hello world' end diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/rubocop/warning.lint-test phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/rubocop/warning.lint-test --- phabricator-0~git20200925/arcanist/src/lint/linter/__tests__/rubocop/warning.lint-test 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/__tests__/rubocop/warning.lint-test 2022-05-17 23:15:03.000000000 +0000 @@ -1,5 +1,7 @@ +# frozen_string_literal: true + def hello(unused) puts 'hi' end ~~~~~~~~~ -warning:1:11 +warning:3:11 diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -17,6 +17,14 @@ continue; } + // Don't warn about PHP comment directives. In particular, we need + // to use "#[\ReturnTypeWillChange]" to implement "Iterator" in a way + // that is compatible with PHP 8.1 and older versions of PHP prior + // to the introduction of return types. See T13588. + if (preg_match('/^#\\[\\\\/', $value)) { + continue; + } + $this->raiseLintAtOffset( $comment->getOffset(), pht( diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistEachUseXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistEachUseXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistEachUseXHPASTLinterRule.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistEachUseXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,24 @@ +getFunctionCalls($root, array('each')); + + foreach ($calls as $call) { + $this->raiseLintAtNode( + $call, + pht( + 'Do not use "each()". This function was deprecated in PHP 7.2 '. + 'and removed in PHP 8.0')); + } + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -94,7 +94,7 @@ $argv = array($format->evalStatic()) + array_fill(0, $argc, null); try { - xsprintf(null, null, $argv); + xsprintf(array(__CLASS__, 'processXsprintfCallback'), null, $argv); } catch (BadFunctionCallException $ex) { $this->raiseLintAtNode( $call, @@ -105,4 +105,23 @@ } } + public static function processXsprintfCallback( + $userdata, + &$pattern, + &$pos, + &$value, + &$length) { + + if ($value !== null) { + throw new Exception('Expected dummy value to be null'); + } + + // Turn format "%$pattern" with argument null into format "%s" with + // argument "%$pattern". This ensures we always provide valid input for + // sprintf to avoid getting a ValueError when using custom format + // specifiers. + $value = '%'.$pattern[$pos]; + $pattern[$pos] = 's'; + } + } diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -22,68 +22,65 @@ $is_final = false; $is_static = false; $visibility = null; + $is_property = ($method->getTypeName() == 'n_CLASS_MEMBER_MODIFIER_LIST'); + $is_method = !$is_property; + + $final_modifier = null; + $visibility_modifier = null; + $abstract_modifier = null; foreach ($modifiers as $modifier) { switch ($modifier->getConcreteString()) { case 'abstract': - if ($method->getTypeName() == 'n_CLASS_MEMBER_MODIFIER_LIST') { + if ($is_property) { $this->raiseLintAtNode( $modifier, pht( - 'Properties cannot be declared `%s`.', - 'abstract')); + 'Properties cannot be declared "abstract".')); } if ($is_abstract) { $this->raiseLintAtNode( $modifier, pht( - 'Multiple `%s` modifiers are not allowed.', - 'abstract')); - } - - if ($is_final) { - $this->raiseLintAtNode( - $modifier, - pht( - 'Cannot use the `%s` modifier on an `%s` class member', - 'final', - 'abstract')); + 'Multiple "abstract" modifiers are not allowed.')); } + $abstract_modifier = $modifier; $is_abstract = true; break; case 'final': - if ($is_abstract) { + if ($is_property) { $this->raiseLintAtNode( $modifier, pht( - 'Cannot use the `%s` modifier on an `%s` class member', - 'final', - 'abstract')); + 'Properties can not be declared "final".')); } if ($is_final) { $this->raiseLintAtNode( $modifier, pht( - 'Multiple `%s` modifiers are not allowed.', - 'final')); + 'Multiple "final" modifiers are not allowed.')); } + $final_modifier = $modifier; $is_final = true; break; case 'public': case 'protected': case 'private': - if ($visibility) { + if ($visibility !== null) { $this->raiseLintAtNode( $modifier, pht('Multiple access type modifiers are not allowed.')); } + $visibility_modifier = $modifier; + $visibility = $modifier->getConcreteString(); + $visibility = phutil_utf8_strtolower($visibility); break; case 'static': @@ -91,12 +88,47 @@ $this->raiseLintAtNode( $modifier, pht( - 'Multiple `%s` modifiers are not allowed.', - 'static')); + 'Multiple "static" modifiers are not allowed.')); } break; } } + + $is_private = ($visibility === 'private'); + + if ($is_final && $is_abstract) { + if ($is_method) { + $this->raiseLintAtNode( + $final_modifier, + pht('Methods may not be both "abstract" and "final".')); + } else { + // Properties can't be "abstract" and "final" either, but they can't + // ever be "abstract" at all, and we've already raise a message about + // that earlier. + } + } + + if ($is_private && $is_final) { + if ($is_method) { + $final_tokens = $final_modifier->getTokens(); + $space_tokens = last($final_tokens)->getWhitespaceTokensAfter(); + + $final_offset = head($final_tokens)->getOffset(); + + $final_string = array_merge($final_tokens, $space_tokens); + $final_string = mpull($final_string, 'getValue'); + $final_string = implode('', $final_string); + + $this->raiseLintAtOffset( + $final_offset, + pht('Methods may not be both "private" and "final".'), + $final_string, + ''); + } else { + // Properties can't be "final" at all, and we already raised a + // message about this. + } + } } } diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistParentMemberReferenceXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistParentMemberReferenceXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistParentMemberReferenceXHPASTLinterRule.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistParentMemberReferenceXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -55,7 +55,12 @@ } } - if (version_compare($this->version, '5.4.0', '>=') || !$in_closure) { + $version_target = $this->version; + if ($version_target === null) { + $version_target = phpversion(); + } + + if (version_compare($version_target, '5.4.0', '>=') || !$in_closure) { $this->raiseLintAtNode( $class_ref, pht( diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistPartialCatchXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistPartialCatchXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistPartialCatchXHPASTLinterRule.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistPartialCatchXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,45 @@ +selectDescendantsOfType('n_CATCH_LIST'); + + foreach ($catch_lists as $catch_list) { + $catches = $catch_list->getChildrenOfType('n_CATCH'); + + $classes = array(); + foreach ($catches as $catch) { + $class_node = $catch->getChildOfType(0, 'n_CLASS_NAME'); + $class_name = $class_node->getConcreteString(); + $class_name = phutil_utf8_strtolower($class_name); + + $classes[$class_name] = $class_node; + } + + $catches_exception = idx($classes, 'exception'); + $catches_throwable = idx($classes, 'throwable'); + + if ($catches_exception && !$catches_throwable) { + $this->raiseLintAtNode( + $catches_exception, + pht( + 'Try/catch block catches "Exception", but does not catch '. + '"Throwable". In PHP7 and newer, some runtime exceptions '. + 'will escape this block.')); + } + } + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -155,7 +155,9 @@ if ($this->windowsVersion) { $windows = idx($compat_info['functions_windows'], $name); - if ($windows === false) { + if ($windows === null) { + // This function has no special Windows considerations. + } else if ($windows === false) { $this->raiseLintAtNode( $node, pht( diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistProductNameLiteralXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistProductNameLiteralXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistProductNameLiteralXHPASTLinterRule.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistProductNameLiteralXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,67 @@ +selectDescendantsOfType('n_FUNCTION_CALL'); + + $product_names = PlatformSymbols::getProductNames(); + foreach ($product_names as $k => $product_name) { + $product_names[$k] = preg_quote($product_name); + } + + $search_pattern = '(\b(?:'.implode('|', $product_names).')\b)i'; + + foreach ($calls as $call) { + $name = $call->getChildByIndex(0)->getConcreteString(); + + if ($name !== 'pht') { + continue; + } + + $parameters = $call->getChildByIndex(1); + + if (!$parameters->getChildren()) { + continue; + } + + $identifier = $parameters->getChildByIndex(0); + if (!$identifier->isConstantString()) { + continue; + } + + $literal_value = $identifier->evalStatic(); + + $matches = phutil_preg_match_all($search_pattern, $literal_value); + if (!$matches[0]) { + continue; + } + + $name_list = array(); + foreach ($matches[0] as $match) { + $name_list[phutil_utf8_strtolower($match)] = $match; + } + $name_list = implode(', ', $name_list); + + $this->raiseLintAtNode( + $identifier, + pht( + 'Avoid use of product name literals in "pht()": use generic '. + 'language or an appropriate method from the "PlatformSymbols" class '. + 'instead so the software can be forked. String uses names: %s.', + $name_list)); + } + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistSelfMemberReferenceXHPASTLinterRule.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistSelfMemberReferenceXHPASTLinterRule.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/ArcanistSelfMemberReferenceXHPASTLinterRule.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/ArcanistSelfMemberReferenceXHPASTLinterRule.php 2022-05-17 23:15:03.000000000 +0000 @@ -42,7 +42,12 @@ } } - if (version_compare($this->version, '5.4.0', '>=') || !$in_closure) { + $version_target = $this->version; + if (!$version_target) { + $version_target = phpversion(); + } + + if (version_compare($version_target, '5.4.0', '>=') || !$in_closure) { $this->raiseLintAtNode( $class_ref, pht( diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistEachUseXHPASTLinterRuleTestCase.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistEachUseXHPASTLinterRuleTestCase.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistEachUseXHPASTLinterRuleTestCase.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistEachUseXHPASTLinterRuleTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,10 @@ +executeTestsInDirectory(dirname(__FILE__).'/each-use/'); + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistPartialCatchXHPASTLinterRuleTestCase.php phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistPartialCatchXHPASTLinterRuleTestCase.php --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistPartialCatchXHPASTLinterRuleTestCase.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/__tests__/ArcanistPartialCatchXHPASTLinterRuleTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,10 @@ +executeTestsInDirectory(dirname(__FILE__).'/partial-catch/'); + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/__tests__/comment-style/hash-directives.lint-test phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/__tests__/comment-style/hash-directives.lint-test --- phabricator-0~git20200925/arcanist/src/lint/linter/xhpast/rules/__tests__/comment-style/hash-directives.lint-test 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/lint/linter/xhpast/rules/__tests__/comment-style/hash-directives.lint-test 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,23 @@ +newTrimmedMessage(); $original = $message->getOriginalText(); + $original = phutil_string_cast($original); + $replacement = $message->getReplacementText(); $line = $message->getLine(); diff -Nru phabricator-0~git20200925/arcanist/src/log/ArcanistLogEngine.php phabricator-0~git20220903/arcanist/src/log/ArcanistLogEngine.php --- phabricator-0~git20200925/arcanist/src/log/ArcanistLogEngine.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/log/ArcanistLogEngine.php 2022-05-17 23:15:03.000000000 +0000 @@ -19,7 +19,7 @@ } private function writeBytes($bytes) { - fprintf(STDERR, '%s', $bytes); + PhutilSystem::writeStderr($bytes); return $this; } diff -Nru phabricator-0~git20200925/arcanist/src/moduleutils/PhutilLibraryMapBuilder.php phabricator-0~git20220903/arcanist/src/moduleutils/PhutilLibraryMapBuilder.php --- phabricator-0~git20200925/arcanist/src/moduleutils/PhutilLibraryMapBuilder.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/moduleutils/PhutilLibraryMapBuilder.php 2022-05-17 23:15:03.000000000 +0000 @@ -12,7 +12,6 @@ final class PhutilLibraryMapBuilder extends Phobject { private $root; - private $quiet = true; private $subprocessLimit = 8; private $fileSymbolMap; @@ -39,19 +38,6 @@ } /** - * Control status output. Use `--quiet` to set this. - * - * @param bool If true, don't show status output. - * @return this - * - * @task map - */ - public function setQuiet($quiet) { - $this->quiet = $quiet; - return $this; - } - - /** * Control subprocess parallelism limit. Use `--limit` to set this. * * @param int Maximum number of subprocesses to run in parallel. @@ -108,25 +94,9 @@ public function buildAndWriteMap() { $library_map = $this->buildMap(); - $this->log(pht('Writing map...')); $this->writeLibraryMap($library_map); } - /** - * Write a status message to the user, if not running in quiet mode. - * - * @param string Message to write. - * @return this - * - * @task map - */ - private function log($message) { - if (!$this->quiet) { - @fwrite(STDERR, "%s\n", $message); - } - return $this; - } - /* -( Path Management )---------------------------------------------------- */ @@ -236,11 +206,7 @@ } $json = json_encode($cache); - try { - Filesystem::writeFile($cache_file, $json); - } catch (FilesystemException $ex) { - $this->log(pht('Unable to save the cache!')); - } + Filesystem::writeFile($cache_file, $json); } /** @@ -251,7 +217,6 @@ * @task symbol */ public function dropSymbolCache() { - $this->log(pht('Dropping symbol cache...')); Filesystem::remove($this->getPathForSymbolCache()); } @@ -266,9 +231,29 @@ */ private function buildSymbolAnalysisFuture($file) { $absolute_file = $this->getPath($file); + return self::newExtractSymbolsFuture( + array(), + array($absolute_file)); + } + + private static function newExtractSymbolsFuture(array $flags, array $paths) { $bin = dirname(__FILE__).'/../../support/lib/extract-symbols.php'; - return new ExecFuture('php -f %R -- --ugly %R', $bin, $absolute_file); + return new ExecFuture( + 'php -f %R -- --ugly %Ls -- %Ls', + $bin, + $flags, + $paths); + } + + public static function newBuiltinMap() { + $future = self::newExtractSymbolsFuture( + array('--builtins'), + array()); + + list($json) = $future->resolvex(); + + return phutil_json_decode($json); } @@ -431,14 +416,10 @@ */ private function analyzeLibrary() { // Identify all the ".php" source files in the library. - $this->log(pht('Finding source files...')); $source_map = $this->loadSourceFileMap(); - $this->log( - pht('Found %s files.', new PhutilNumber(count($source_map)))); // Load the symbol cache with existing parsed symbols. This allows us // to remap libraries quickly by analyzing only changed files. - $this->log(pht('Loading symbol cache...')); $symbol_cache = $this->loadSymbolCache(); // If the XHPAST binary is not up-to-date, build it now. Otherwise, @@ -461,23 +442,12 @@ } $futures[$file] = $this->buildSymbolAnalysisFuture($file); } - $this->log( - pht('Found %s files in cache.', new PhutilNumber(count($symbol_map)))); // Run the analyzer on any files which need analysis. if ($futures) { $limit = $this->subprocessLimit; - $this->log( - pht( - 'Analyzing %s file(s) with %s subprocess(es)...', - phutil_count($futures), - new PhutilNumber($limit))); - $progress = new PhutilConsoleProgressBar(); - if ($this->quiet) { - $progress->setQuiet(true); - } $progress->setTotal(count($futures)); $futures = id(new FutureIterator($futures)) @@ -505,8 +475,6 @@ $this->writeSymbolCache($symbol_map, $source_map); // Our map is up to date, so either show it on stdout or write it to disk. - $this->log(pht('Building library map...')); - $this->librarySymbolMap = $this->buildLibraryMap($symbol_map); } diff -Nru phabricator-0~git20200925/arcanist/src/object/Phobject.php phabricator-0~git20220903/arcanist/src/object/Phobject.php --- phabricator-0~git20200925/arcanist/src/object/Phobject.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/object/Phobject.php 2022-05-17 23:15:03.000000000 +0000 @@ -33,22 +33,27 @@ get_class($this).'::'.$name)); } + #[\ReturnTypeWillChange] public function current() { $this->throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function key() { $this->throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function next() { $this->throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function rewind() { $this->throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function valid() { $this->throwOnAttemptedIteration(); } diff -Nru phabricator-0~git20200925/arcanist/src/parser/aast/api/AASTNodeList.php phabricator-0~git20220903/arcanist/src/parser/aast/api/AASTNodeList.php --- phabricator-0~git20200925/arcanist/src/parser/aast/api/AASTNodeList.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/aast/api/AASTNodeList.php 2022-05-17 23:15:03.000000000 +0000 @@ -80,6 +80,7 @@ /* -( Countable )---------------------------------------------------------- */ + #[\ReturnTypeWillChange] public function count() { return count($this->ids); } @@ -87,22 +88,27 @@ /* -( Iterator )----------------------------------------------------------- */ + #[\ReturnTypeWillChange] public function current() { return $this->list[$this->key()]; } + #[\ReturnTypeWillChange] public function key() { return $this->ids[$this->pos]; } + #[\ReturnTypeWillChange] public function next() { $this->pos++; } + #[\ReturnTypeWillChange] public function rewind() { $this->pos = 0; } + #[\ReturnTypeWillChange] public function valid() { return $this->pos < count($this->ids); } diff -Nru phabricator-0~git20200925/arcanist/src/parser/aast/api/AASTToken.php phabricator-0~git20220903/arcanist/src/parser/aast/api/AASTToken.php --- phabricator-0~git20200925/arcanist/src/parser/aast/api/AASTToken.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/aast/api/AASTToken.php 2022-05-17 23:15:03.000000000 +0000 @@ -84,6 +84,17 @@ return $result; } + public function getWhitespaceTokensAfter() { + $tokens = $this->tree->getRawTokenStream(); + $result = array(); + $ii = $this->id + 1; + while ($ii < count($tokens) && $tokens[$ii]->isAnyWhitespace()) { + $result[$ii] = $tokens[$ii]; + ++$ii; + } + return $result; + } + final public function getLineNumber() { return idx($this->tree->getOffsetToLineNumberMap(), $this->getOffset()); } diff -Nru phabricator-0~git20200925/arcanist/src/parser/ArcanistBaseCommitParser.php phabricator-0~git20220903/arcanist/src/parser/ArcanistBaseCommitParser.php --- phabricator-0~git20200925/arcanist/src/parser/ArcanistBaseCommitParser.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/ArcanistBaseCommitParser.php 2022-05-17 23:15:03.000000000 +0000 @@ -33,7 +33,7 @@ private function log($message) { if ($this->verbose) { - fwrite(STDERR, $message."\n"); + PhutilSystem::writeStderr($message."\n"); } } diff -Nru phabricator-0~git20200925/arcanist/src/parser/ArcanistBundle.php phabricator-0~git20220903/arcanist/src/parser/ArcanistBundle.php --- phabricator-0~git20200925/arcanist/src/parser/ArcanistBundle.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/ArcanistBundle.php 2022-05-17 23:15:03.000000000 +0000 @@ -639,8 +639,7 @@ $old_path = $change->getOldPath(); $type = $change->getType(); - if (!strlen($old_path) || - $type == ArcanistDiffChangeType::TYPE_ADD) { + if ($old_path === '' || $type == ArcanistDiffChangeType::TYPE_ADD) { $old_path = null; } @@ -1023,7 +1022,7 @@ if ($is_64bit) { for ($count = 4; $count >= 0; $count--) { $val = $accum % 85; - $accum = $accum / 85; + $accum = (int)($accum / 85); $slice .= $map[$val]; } } else { diff -Nru phabricator-0~git20200925/arcanist/src/parser/ArcanistDiffParser.php phabricator-0~git20220903/arcanist/src/parser/ArcanistDiffParser.php --- phabricator-0~git20200925/arcanist/src/parser/ArcanistDiffParser.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/ArcanistDiffParser.php 2022-05-17 23:15:03.000000000 +0000 @@ -217,7 +217,7 @@ $line = $this->nextLine(); } - if (strlen($message)) { + if ($message !== null && strlen($message)) { // If we found a message during pre-parse steps, add it to the resulting // changes here. $change = $this->buildChange(null) @@ -582,10 +582,13 @@ $ok = false; $match = null; - foreach ($patterns as $pattern) { - $ok = preg_match('@^'.$pattern.'@', $line, $match); - if ($ok) { - break; + + if ($line !== null) { + foreach ($patterns as $pattern) { + $ok = preg_match('@^'.$pattern.'@', $line, $match); + if ($ok) { + break; + } } } @@ -774,7 +777,7 @@ $this->nextLine(); $this->parseGitBinaryPatch(); $line = $this->getLine(); - if (preg_match('/^literal/', $line)) { + if ($line !== null && preg_match('/^literal/', $line)) { // We may have old/new binaries (change) or just a new binary (hg add). // If there are two blocks, parse both. $this->parseGitBinaryPatch(); @@ -920,11 +923,11 @@ $hunk->setNewOffset($matches[3]); // Cover for the cases where length wasn't present (implying one line). - $old_len = idx($matches, 2); + $old_len = idx($matches, 2, ''); if (!strlen($old_len)) { $old_len = 1; } - $new_len = idx($matches, 4); + $new_len = idx($matches, 4, ''); if (!strlen($new_len)) { $new_len = 1; } @@ -1041,7 +1044,7 @@ $line = $this->nextNonemptyLine(); } - } while (preg_match('/^@@ /', $line)); + } while (($line !== null) && preg_match('/^@@ /', $line)); } protected function buildChange($path = null) { diff -Nru phabricator-0~git20200925/arcanist/src/parser/argument/PhutilArgumentParser.php phabricator-0~git20220903/arcanist/src/parser/argument/PhutilArgumentParser.php --- phabricator-0~git20200925/arcanist/src/parser/argument/PhutilArgumentParser.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/argument/PhutilArgumentParser.php 2022-05-17 23:15:03.000000000 +0000 @@ -625,6 +625,33 @@ return $this->specs[$name]->getDefault(); } + public function getArgAsInteger($name) { + $value = $this->getArg($name); + + if ($value === null) { + return $value; + } + + if (!preg_match('/^-?\d+\z/', $value)) { + throw new PhutilArgumentUsageException( + pht( + 'Parameter provided to argument "--%s" must be an integer.', + $name)); + } + + $intvalue = (int)$value; + + if (phutil_string_cast($intvalue) !== phutil_string_cast($value)) { + throw new PhutilArgumentUsageException( + pht( + 'Parameter provided to argument "--%s" is too large to '. + 'parse as an integer.', + $name)); + } + + return $intvalue; + } + public function getUnconsumedArgumentVector() { return $this->argv; } @@ -769,7 +796,12 @@ pht('There is no **%s** workflow.', $workflow_name)); } else { $out[] = $this->indent($indent, $workflow->getExamples()); - $out[] = $this->indent($indent, $workflow->getSynopsis()); + + $synopsis = $workflow->getSynopsis(); + if ($synopsis !== null) { + $out[] = $this->indent($indent, $workflow->getSynopsis()); + } + if ($show_details) { $full_help = $workflow->getHelp(); if ($full_help) { @@ -800,7 +832,7 @@ private function logMessage($message) { - fwrite(STDERR, $message); + PhutilSystem::writeStderr($message); } diff -Nru phabricator-0~git20200925/arcanist/src/parser/PhutilBugtraqParser.php phabricator-0~git20220903/arcanist/src/parser/PhutilBugtraqParser.php --- phabricator-0~git20200925/arcanist/src/parser/PhutilBugtraqParser.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/PhutilBugtraqParser.php 2022-05-17 23:15:03.000000000 +0000 @@ -85,7 +85,7 @@ $captured_text = $capture['text']; $captured_offset = $capture['at']; - if (strlen($select_regexp)) { + if ($select_regexp !== null) { $selections = null; preg_match_all( $select_regexp, diff -Nru phabricator-0~git20200925/arcanist/src/parser/PhutilEmailAddress.php phabricator-0~git20220903/arcanist/src/parser/PhutilEmailAddress.php --- phabricator-0~git20200925/arcanist/src/parser/PhutilEmailAddress.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/PhutilEmailAddress.php 2022-05-17 23:15:03.000000000 +0000 @@ -13,6 +13,7 @@ private $domainName; public function __construct($email_address = null) { + $email_address = phutil_string_cast($email_address); $email_address = trim($email_address); $matches = null; @@ -41,12 +42,13 @@ public function __toString() { $address = $this->getAddress(); - if (strlen($this->displayName)) { + + if (phutil_nonempty_string($this->displayName)) { $display_name = $this->encodeDisplayName($this->displayName); return $display_name.' <'.$address.'>'; - } else { - return $address; } + + return $address; } public function setDisplayName($display_name) { @@ -89,7 +91,7 @@ public function getAddress() { $address = $this->localPart; - if (strlen($this->domainName)) { + if ($this->domainName !== null && strlen($this->domainName)) { $address .= '@'.$this->domainName; } return $address; diff -Nru phabricator-0~git20200925/arcanist/src/parser/PhutilJSON.php phabricator-0~git20220903/arcanist/src/parser/PhutilJSON.php --- phabricator-0~git20200925/arcanist/src/parser/PhutilJSON.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/PhutilJSON.php 2022-05-17 23:15:03.000000000 +0000 @@ -19,7 +19,7 @@ * @param dict An object to encode in JSON. * @return string Pretty-printed object representation. */ - public function encodeFormatted(array $object) { + public function encodeFormatted($object) { return $this->encodeFormattedObject($object, 0)."\n"; } @@ -47,6 +47,10 @@ * @task internal */ private function encodeFormattedObject($object, $depth) { + if ($object instanceof stdClass) { + $object = (array)$object; + } + if (empty($object)) { return '{}'; } @@ -123,6 +127,8 @@ } else { return $this->encodeFormattedObject($value, $depth); } + } else if (is_object($value)) { + return $this->encodeFormattedObject($value, $depth); } else { if (defined('JSON_UNESCAPED_SLASHES')) { // If we have a new enough version of PHP, disable escaping of slashes diff -Nru phabricator-0~git20200925/arcanist/src/parser/PhutilTypeSpec.php phabricator-0~git20220903/arcanist/src/parser/PhutilTypeSpec.php --- phabricator-0~git20200925/arcanist/src/parser/PhutilTypeSpec.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/PhutilTypeSpec.php 2022-05-17 23:15:03.000000000 +0000 @@ -75,6 +75,10 @@ } break; case 'regex': + if (!is_string($value)) { + throw new PhutilTypeCheckException($this, $value, $name); + } + $trap = new PhutilErrorTrap(); $ok = @preg_match($value, ''); $err = $trap->getErrorsAsString(); diff -Nru phabricator-0~git20200925/arcanist/src/parser/PhutilURI.php phabricator-0~git20220903/arcanist/src/parser/PhutilURI.php --- phabricator-0~git20200925/arcanist/src/parser/PhutilURI.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/PhutilURI.php 2022-05-17 23:15:03.000000000 +0000 @@ -154,9 +154,9 @@ $user = $this->user; $pass = $this->pass; - if (strlen($user) && strlen($pass)) { + if (phutil_nonempty_string($user) && phutil_nonempty_string($pass)) { $auth = rawurlencode($user).':'.rawurlencode($pass).'@'; - } else if (strlen($user)) { + } else if (phutil_nonempty_string($user)) { $auth = rawurlencode($user).'@'; } else { $auth = null; @@ -166,19 +166,24 @@ if ($this->isGitURI()) { $protocol = null; } else { - if (strlen($auth)) { + if ($auth !== null) { $protocol = nonempty($this->protocol, 'http'); } } - if (strlen($protocol) || strlen($auth) || strlen($domain)) { + $has_protocol = ($protocol !== null) && strlen($protocol); + $has_auth = ($auth !== null); + $has_domain = ($domain !== null) && strlen($domain); + $has_port = ($port !== null) && strlen($port); + + if ($has_protocol || $has_auth || $has_domain) { if ($this->isGitURI()) { $prefix = "{$auth}{$domain}"; } else { $prefix = "{$protocol}://{$auth}{$domain}"; } - if (strlen($port)) { + if ($has_port) { $prefix .= ':'.$port; } } @@ -189,7 +194,7 @@ $query = null; } - if (strlen($this->getFragment())) { + if (phutil_nonempty_string($this->getFragment())) { $fragment = '#'.$this->getFragment(); } else { $fragment = null; @@ -428,7 +433,7 @@ if ($this->isGitURI()) { // Git URIs use relative paths which do not need to begin with "/". } else { - if ($this->domain && strlen($path) && $path[0] !== '/') { + if ($this->domain && phutil_nonempty_string($path) && $path[0] !== '/') { $path = '/'.$path; } } diff -Nru phabricator-0~git20200925/arcanist/src/parser/__tests__/PhutilJSONTestCase.php phabricator-0~git20220903/arcanist/src/parser/__tests__/PhutilJSONTestCase.php --- phabricator-0~git20200925/arcanist/src/parser/__tests__/PhutilJSONTestCase.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/parser/__tests__/PhutilJSONTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -18,4 +18,33 @@ pht('Empty arrays should serialize as `%s`, not `%s`.', '[]', '{}')); } + public function testNestedObjectEncoding() { + $expect = <<duck = 'quack'; + + $input = (object)array( + 'empty-object' => $empty_object, + 'pair-object' => $pair_object, + ); + + $serializer = new PhutilJSON(); + + $this->assertEqual( + $expect, + $serializer->encodeFormatted($input), + pht('Serialization of PHP-object JSON values.')); + } + } diff -Nru phabricator-0~git20200925/arcanist/src/__phutil_library_map__.php phabricator-0~git20220903/arcanist/src/__phutil_library_map__.php --- phabricator-0~git20200925/arcanist/src/__phutil_library_map__.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/__phutil_library_map__.php 2022-05-17 23:15:03.000000000 +0000 @@ -188,6 +188,8 @@ 'ArcanistDuplicateSwitchCaseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDuplicateSwitchCaseXHPASTLinterRuleTestCase.php', 'ArcanistDynamicDefineXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDynamicDefineXHPASTLinterRule.php', 'ArcanistDynamicDefineXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDynamicDefineXHPASTLinterRuleTestCase.php', + 'ArcanistEachUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistEachUseXHPASTLinterRule.php', + 'ArcanistEachUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistEachUseXHPASTLinterRuleTestCase.php', 'ArcanistElseIfUsageXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistElseIfUsageXHPASTLinterRule.php', 'ArcanistElseIfUsageXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistElseIfUsageXHPASTLinterRuleTestCase.php', 'ArcanistEmptyFileXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistEmptyFileXHPASTLinterRule.php', @@ -264,6 +266,8 @@ 'ArcanistHgProxyClient' => 'hgdaemon/ArcanistHgProxyClient.php', 'ArcanistHgProxyServer' => 'hgdaemon/ArcanistHgProxyServer.php', 'ArcanistHgServerChannel' => 'hgdaemon/ArcanistHgServerChannel.php', + 'ArcanistHostMemorySnapshot' => 'filesystem/memory/ArcanistHostMemorySnapshot.php', + 'ArcanistHostMemorySnapshotTestCase' => 'filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php', 'ArcanistImplicitConstructorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitConstructorXHPASTLinterRule.php', 'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitConstructorXHPASTLinterRuleTestCase.php', 'ArcanistImplicitFallthroughXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitFallthroughXHPASTLinterRule.php', @@ -346,6 +350,7 @@ 'ArcanistMercurialAPI' => 'repository/api/ArcanistMercurialAPI.php', 'ArcanistMercurialCommitGraphQuery' => 'repository/graph/query/ArcanistMercurialCommitGraphQuery.php', 'ArcanistMercurialCommitMessageHardpointQuery' => 'query/ArcanistMercurialCommitMessageHardpointQuery.php', + 'ArcanistMercurialCommitSymbolCommitHardpointQuery' => 'ref/commit/ArcanistMercurialCommitSymbolCommitHardpointQuery.php', 'ArcanistMercurialLandEngine' => 'land/engine/ArcanistMercurialLandEngine.php', 'ArcanistMercurialLocalState' => 'repository/state/ArcanistMercurialLocalState.php', 'ArcanistMercurialParser' => 'repository/parser/ArcanistMercurialParser.php', @@ -378,6 +383,7 @@ 'ArcanistNoParentScopeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNoParentScopeXHPASTLinterRule.php', 'ArcanistNoParentScopeXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNoParentScopeXHPASTLinterRuleTestCase.php', 'ArcanistNoURIConduitException' => 'conduit/ArcanistNoURIConduitException.php', + 'ArcanistNonblockingGuard' => 'utils/ArcanistNonblockingGuard.php', 'ArcanistNoneLintRenderer' => 'lint/renderer/ArcanistNoneLintRenderer.php', 'ArcanistObjectListHardpoint' => 'hardpoint/ArcanistObjectListHardpoint.php', 'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php', @@ -402,6 +408,8 @@ 'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParenthesesSpacingXHPASTLinterRuleTestCase.php', 'ArcanistParseStrUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParseStrUseXHPASTLinterRule.php', 'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParseStrUseXHPASTLinterRuleTestCase.php', + 'ArcanistPartialCatchXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPartialCatchXHPASTLinterRule.php', + 'ArcanistPartialCatchXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPartialCatchXHPASTLinterRuleTestCase.php', 'ArcanistPasteRef' => 'ref/paste/ArcanistPasteRef.php', 'ArcanistPasteSymbolRef' => 'ref/paste/ArcanistPasteSymbolRef.php', 'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php', @@ -416,6 +424,7 @@ 'ArcanistPhutilXHPASTLinterStandard' => 'lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php', 'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPlusOperatorOnStringsXHPASTLinterRule.php', 'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase.php', + 'ArcanistProductNameLiteralXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistProductNameLiteralXHPASTLinterRule.php', 'ArcanistProjectConfigurationSource' => 'config/source/ArcanistProjectConfigurationSource.php', 'ArcanistPrompt' => 'toolset/ArcanistPrompt.php', 'ArcanistPromptResponse' => 'toolset/ArcanistPromptResponse.php', @@ -629,6 +638,8 @@ 'LinesOfALargeFile' => 'filesystem/linesofalarge/LinesOfALargeFile.php', 'LinesOfALargeFileTestCase' => 'filesystem/linesofalarge/__tests__/LinesOfALargeFileTestCase.php', 'MFilterTestHelper' => 'utils/__tests__/MFilterTestHelper.php', + 'MethodCallFuture' => 'future/MethodCallFuture.php', + 'MethodCallFutureTestCase' => 'future/__tests__/MethodCallFutureTestCase.php', 'NoseTestEngine' => 'unit/engine/NoseTestEngine.php', 'PHPASTParserTestCase' => 'parser/xhpast/__tests__/PHPASTParserTestCase.php', 'PhageAction' => 'phage/action/PhageAction.php', @@ -742,6 +753,7 @@ 'PhutilEnglishCanadaLocale' => 'internationalization/locales/PhutilEnglishCanadaLocale.php', 'PhutilErrorHandler' => 'error/PhutilErrorHandler.php', 'PhutilErrorHandlerTestCase' => 'error/__tests__/PhutilErrorHandlerTestCase.php', + 'PhutilErrorLog' => 'filesystem/PhutilErrorLog.php', 'PhutilErrorTrap' => 'error/PhutilErrorTrap.php', 'PhutilEvent' => 'events/PhutilEvent.php', 'PhutilEventConstants' => 'events/constant/PhutilEventConstants.php', @@ -762,6 +774,7 @@ 'PhutilGitHubResponse' => 'future/github/PhutilGitHubResponse.php', 'PhutilGitURI' => 'parser/PhutilGitURI.php', 'PhutilGitURITestCase' => 'parser/__tests__/PhutilGitURITestCase.php', + 'PhutilGitsprintfTestCase' => 'xsprintf/__tests__/PhutilGitsprintfTestCase.php', 'PhutilHTMLParser' => 'parser/html/PhutilHTMLParser.php', 'PhutilHTMLParserTestCase' => 'parser/html/__tests__/PhutilHTMLParserTestCase.php', 'PhutilHTTPEngineExtension' => 'future/http/PhutilHTTPEngineExtension.php', @@ -846,6 +859,7 @@ 'PhutilRawEnglishLocale' => 'internationalization/locales/PhutilRawEnglishLocale.php', 'PhutilReadableSerializer' => 'readableserializer/PhutilReadableSerializer.php', 'PhutilReadableSerializerTestCase' => 'readableserializer/__tests__/PhutilReadableSerializerTestCase.php', + 'PhutilRegexException' => 'exception/PhutilRegexException.php', 'PhutilRope' => 'utils/PhutilRope.php', 'PhutilRopeTestCase' => 'utils/__tests__/PhutilRopeTestCase.php', 'PhutilServiceProfiler' => 'serviceprofiler/PhutilServiceProfiler.php', @@ -901,6 +915,7 @@ 'PhutilVeryWowEnglishLocale' => 'internationalization/locales/PhutilVeryWowEnglishLocale.php', 'PhutilWordPressFuture' => 'future/wordpress/PhutilWordPressFuture.php', 'PhutilXHPASTBinary' => 'parser/xhpast/bin/PhutilXHPASTBinary.php', + 'PlatformSymbols' => 'platform/PlatformSymbols.php', 'PytestTestEngine' => 'unit/engine/PytestTestEngine.php', 'TempFile' => 'filesystem/TempFile.php', 'TestAbstractDirectedGraph' => 'utils/__tests__/TestAbstractDirectedGraph.php', @@ -927,6 +942,7 @@ 'csprintf' => 'xsprintf/csprintf.php', 'exec_manual' => 'future/exec/execx.php', 'execx' => 'future/exec/execx.php', + 'gitsprintf' => 'xsprintf/gitsprintf.php', 'head' => 'utils/utils.php', 'head_key' => 'utils/utils.php', 'hgsprintf' => 'xsprintf/hgsprintf.php', @@ -952,6 +968,7 @@ 'nonempty' => 'utils/utils.php', 'phlog' => 'error/phlog.php', 'pht' => 'internationalization/pht.php', + 'pht_list' => 'internationalization/pht.php', 'phutil_build_http_querystring' => 'utils/utils.php', 'phutil_build_http_querystring_from_pairs' => 'utils/utils.php', 'phutil_censor_credentials' => 'utils/utils.php', @@ -965,7 +982,6 @@ 'phutil_count' => 'internationalization/pht.php', 'phutil_date_format' => 'utils/viewutils.php', 'phutil_decode_mime_header' => 'utils/utils.php', - 'phutil_deprecated' => 'init/lib/moduleutils.php', 'phutil_describe_type' => 'utils/utils.php', 'phutil_encode_log' => 'utils/utils.php', 'phutil_error_listener_example' => 'error/phlog.php', @@ -1001,10 +1017,16 @@ 'phutil_load_library' => 'init/lib/moduleutils.php', 'phutil_loggable_string' => 'utils/utils.php', 'phutil_microseconds_since' => 'utils/utils.php', + 'phutil_nonempty_scalar' => 'utils/utils.php', + 'phutil_nonempty_string' => 'utils/utils.php', + 'phutil_nonempty_stringlike' => 'utils/utils.php', 'phutil_parse_bytes' => 'utils/viewutils.php', 'phutil_partition' => 'utils/utils.php', 'phutil_passthru' => 'future/exec/execx.php', 'phutil_person' => 'internationalization/pht.php', + 'phutil_preg_match' => 'utils/utils.php', + 'phutil_preg_match_all' => 'utils/utils.php', + 'phutil_raise_preg_exception' => 'utils/utils.php', 'phutil_register_library' => 'init/lib/core.php', 'phutil_register_library_map' => 'init/lib/core.php', 'phutil_set_system_locale' => 'utils/utf8.php', @@ -1043,6 +1065,7 @@ 'xsprintf' => 'xsprintf/xsprintf.php', 'xsprintf_callback_example' => 'xsprintf/xsprintf.php', 'xsprintf_command' => 'xsprintf/csprintf.php', + 'xsprintf_git' => 'xsprintf/gitsprintf.php', 'xsprintf_javascript' => 'xsprintf/jsprintf.php', 'xsprintf_ldap' => 'xsprintf/ldapsprintf.php', 'xsprintf_mercurial' => 'xsprintf/hgsprintf.php', @@ -1234,6 +1257,8 @@ 'ArcanistDuplicateSwitchCaseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistDynamicDefineXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistDynamicDefineXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', + 'ArcanistEachUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistEachUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistElseIfUsageXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistElseIfUsageXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistEmptyFileXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', @@ -1310,6 +1335,8 @@ 'ArcanistHgProxyClient' => 'Phobject', 'ArcanistHgProxyServer' => 'Phobject', 'ArcanistHgServerChannel' => 'PhutilProtocolChannel', + 'ArcanistHostMemorySnapshot' => 'Phobject', + 'ArcanistHostMemorySnapshotTestCase' => 'PhutilTestCase', 'ArcanistImplicitConstructorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistImplicitFallthroughXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', @@ -1392,6 +1419,7 @@ 'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI', 'ArcanistMercurialCommitGraphQuery' => 'ArcanistCommitGraphQuery', 'ArcanistMercurialCommitMessageHardpointQuery' => 'ArcanistWorkflowMercurialHardpointQuery', + 'ArcanistMercurialCommitSymbolCommitHardpointQuery' => 'ArcanistWorkflowMercurialHardpointQuery', 'ArcanistMercurialLandEngine' => 'ArcanistLandEngine', 'ArcanistMercurialLocalState' => 'ArcanistRepositoryLocalState', 'ArcanistMercurialParser' => 'Phobject', @@ -1424,6 +1452,7 @@ 'ArcanistNoParentScopeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistNoParentScopeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistNoURIConduitException' => 'ArcanistConduitException', + 'ArcanistNonblockingGuard' => 'Phobject', 'ArcanistNoneLintRenderer' => 'ArcanistLintRenderer', 'ArcanistObjectListHardpoint' => 'ArcanistHardpoint', 'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', @@ -1448,6 +1477,8 @@ 'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistParseStrUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', + 'ArcanistPartialCatchXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistPartialCatchXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistPasteRef' => 'ArcanistRef', 'ArcanistPasteSymbolRef' => 'ArcanistSimpleSymbolRef', 'ArcanistPasteWorkflow' => 'ArcanistArcWorkflow', @@ -1462,6 +1493,7 @@ 'ArcanistPhutilXHPASTLinterStandard' => 'ArcanistLinterStandard', 'ArcanistPlusOperatorOnStringsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', + 'ArcanistProductNameLiteralXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistProjectConfigurationSource' => 'ArcanistWorkingCopyConfigurationSource', 'ArcanistPrompt' => 'Phobject', 'ArcanistPromptResponse' => 'Phobject', @@ -1682,6 +1714,8 @@ 'LinesOfALargeFile' => 'LinesOfALarge', 'LinesOfALargeFileTestCase' => 'PhutilTestCase', 'MFilterTestHelper' => 'Phobject', + 'MethodCallFuture' => 'Future', + 'MethodCallFutureTestCase' => 'PhutilTestCase', 'NoseTestEngine' => 'ArcanistUnitTestEngine', 'PHPASTParserTestCase' => 'PhutilTestCase', 'PhageAction' => 'Phobject', @@ -1805,6 +1839,7 @@ 'PhutilEnglishCanadaLocale' => 'PhutilLocale', 'PhutilErrorHandler' => 'Phobject', 'PhutilErrorHandlerTestCase' => 'PhutilTestCase', + 'PhutilErrorLog' => 'Phobject', 'PhutilErrorTrap' => 'Phobject', 'PhutilEvent' => 'Phobject', 'PhutilEventConstants' => 'Phobject', @@ -1825,6 +1860,7 @@ 'PhutilGitHubResponse' => 'Phobject', 'PhutilGitURI' => 'Phobject', 'PhutilGitURITestCase' => 'PhutilTestCase', + 'PhutilGitsprintfTestCase' => 'PhutilTestCase', 'PhutilHTMLParser' => 'Phobject', 'PhutilHTMLParserTestCase' => 'PhutilTestCase', 'PhutilHTTPEngineExtension' => 'Phobject', @@ -1917,6 +1953,7 @@ 'PhutilRawEnglishLocale' => 'PhutilLocale', 'PhutilReadableSerializer' => 'Phobject', 'PhutilReadableSerializerTestCase' => 'PhutilTestCase', + 'PhutilRegexException' => 'Exception', 'PhutilRope' => 'Phobject', 'PhutilRopeTestCase' => 'PhutilTestCase', 'PhutilServiceProfiler' => 'Phobject', @@ -1974,6 +2011,7 @@ 'PhutilVeryWowEnglishLocale' => 'PhutilLocale', 'PhutilWordPressFuture' => 'FutureProxy', 'PhutilXHPASTBinary' => 'Phobject', + 'PlatformSymbols' => 'Phobject', 'PytestTestEngine' => 'ArcanistUnitTestEngine', 'TempFile' => 'Phobject', 'TestAbstractDirectedGraph' => 'AbstractDirectedGraph', diff -Nru phabricator-0~git20200925/arcanist/src/platform/PlatformSymbols.php phabricator-0~git20220903/arcanist/src/platform/PlatformSymbols.php --- phabricator-0~git20200925/arcanist/src/platform/PlatformSymbols.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/platform/PlatformSymbols.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,21 @@ +execFutureLocal( 'log -n1 --format=%s %s --', '%s%n%n%b', - $hash); + gitsprintf('%s', $hash)); } yield $this->yieldFutures($futures); diff -Nru phabricator-0~git20200925/arcanist/src/ref/commit/ArcanistMercurialCommitSymbolCommitHardpointQuery.php phabricator-0~git20220903/arcanist/src/ref/commit/ArcanistMercurialCommitSymbolCommitHardpointQuery.php --- phabricator-0~git20200925/arcanist/src/ref/commit/ArcanistMercurialCommitSymbolCommitHardpointQuery.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/ref/commit/ArcanistMercurialCommitSymbolCommitHardpointQuery.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,204 @@ + $ref) { + $symbol_map[$key] = $ref->getSymbol(); + } + + $symbol_set = array_fuse($symbol_map); + foreach ($symbol_set as $symbol) { + $this->validateSymbol($symbol); + } + + $api = $this->getRepositoryAPI(); + + // Using "hg log" with repeated "--rev arguments will have the following + // behaviors which need accounted for: + // 1. If any one revision is invalid then the entire command will fail. To + // work around this the revset uses a trick where specifying a pattern + // for the bookmark() or tag() predicates instead of a literal won't + // result in failure if the pattern isn't found. + // 2. Multiple markers that resolve to the same node will only be included + // once in the output. Because of this the order of output can't be + // relied upon to match up with the requested symbol. To work around + // this, the template used must also output any associated symbols to + // match back to. Because of this there is no reasonable way to resolve + // symbols with Mercurial-supported modifiers such as 'symbol^'. + // 3. The working directory can't be identified directly, instead a special + // template conditional is used to include 'CWD' as the second item in + // the output if the node is also the working directory, or 'NOTCWD' + // otherwise. This needs included before the tags/bookmarks in order to + // distinguish it from some repository using that same name for a tag or + // bookmark. + + $pattern = array(); + $arguments = array(); + + $pattern[] = 'log'; + + $pattern[] = '--template %s'; + $arguments[] = "{rev}\1". + "{node}\1". + "{ifcontains(rev, revset('parents()'), 'CWD', 'NOTCWD')}\1". + "{tags % '{tag}\2'}{bookmarks % '{bookmark}\2'}\3"; + + foreach ($symbol_set as $symbol) { + // This is the one symbol that wouldn't be a bookmark or tag + if ($symbol === '.') { + $pattern[] = '--rev .'; + continue; + } + + $predicates = array(); + + if (ctype_xdigit($symbol)) { + // Commit hashes are 40 characters + if (strlen($symbol) <= 40) { + $predicates[] = hgsprintf('id("%s")', $symbol); + } + } + + if (ctype_digit($symbol)) { + // This is 2^32-1 which is (typically) the maximum size of an int in + // Python -- passing anything higher than this to rev() will result + // in a Python exception. + if ($symbol <= 2147483647) { + $predicates[] = hgsprintf('rev("%s")', $symbol); + } + } else { + // Mercurial disallows using numbers as marker names. + $re_symbol = preg_quote($symbol); + $predicates[] = hgsprintf('bookmark("re:^%s$")', $re_symbol); + $predicates[] = hgsprintf('tag("re:^%s$")', $re_symbol); + } + + $pattern[] = '--rev %s'; + $arguments[] = implode(' or ', $predicates); + } + + $pattern = implode(' ', $pattern); + array_unshift($arguments, $pattern); + + $future = call_user_func_array( + array($api, 'newFuture'), + $arguments); + + list($stdout) = (yield $this->yieldFuture($future)); + + $lines = explode("\3", $stdout); + + $hash_map = array(); + $node_list = array(); + + foreach ($lines as $line) { + $parts = explode("\1", $line, 4); + + if (empty(array_filter($parts))) { + continue; + } else if (count($parts) === 3) { + list($rev, $node, $cwd) = $parts; + $markers = array(); + } else if (count($parts) === 4) { + list($rev, $node, $cwd, $markers) = $parts; + $markers = array_filter(explode("\2", $markers)); + } else { + throw new Exception( + pht('Execution of "hg log" emitted an unexpected line ("%s").', + $line)); + } + + $node_list[] = $node; + + if (in_array($rev, $symbol_set)) { + if (!isset($hash_map[$rev])) { + $hash_map[$rev] = $node; + } else if ($hash_map[$rev] !== $node) { + $hash_map[$rev] = ''; + } + } + + foreach ($markers as $marker) { + if (!isset($hash_map[$marker])) { + $hash_map[$marker] = $node; + } else if ($hash_map[$marker] !== $node) { + $hash_map[$marker] = ''; + } + } + + // The log template will mark the working directory node with 'CWD' which + // we insert for the special marker '.' for the working directory, used + // by ArcanistMercurialAPI::newCurrentCommitSymbol(). + if ($cwd === 'CWD') { + if (!isset($hash_map['.'])) { + $hash_map['.'] = $node; + } else if ($hash_map['.'] !== $node) { + $hash_map['.'] = ''; + } + } + } + + // Changeset hashes can be prefixes but also collide with other markers. + // Consider 'cafe' which could be a bookmark or also a changeset hash + // prefix. Mercurial will always allow markers to take precedence over + // changeset hashes when resolving, so only populate symbols that match + // hashes after all other entries are populated, to avoid the hash taing + // a spot which a marker might match. + foreach ($node_list as $node) { + foreach ($symbol_set as $symbol) { + if (strncmp($node, $symbol, strlen($symbol)) === 0) { + if (!isset($hash_map[$symbol])) { + $hash_map[$symbol] = $node; + } + } + } + } + + // Remove entries resulting in collisions, which set empty string values + $hash_map = array_filter($hash_map); + + $results = array(); + foreach ($symbol_map as $key => $symbol) { + if (isset($hash_map[$symbol])) { + $results[$key] = $hash_map[$symbol]; + } + } + + foreach ($results as $key => $result) { + if ($result === null) { + continue; + } + + $ref = id(new ArcanistCommitRef()) + ->setCommitHash($result); + + $results[$key] = $ref; + } + + yield $this->yieldMap($results); + } + + private function validateSymbol($symbol) { + if (strpos($symbol, "\n") !== false) { + throw new Exception( + pht( + 'Commit symbol "%s" contains a newline. This is not a valid '. + 'character in a Mercurial commit symbol.', + addcslashes($symbol, "\\\n"))); + } + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/repository/api/ArcanistGitAPI.php phabricator-0~git20220903/arcanist/src/repository/api/ArcanistGitAPI.php --- phabricator-0~git20200925/arcanist/src/repository/api/ArcanistGitAPI.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/repository/api/ArcanistGitAPI.php 2022-05-17 23:15:03.000000000 +0000 @@ -88,7 +88,7 @@ */ private function isDescendant($child, $parent) { list($common_ancestor) = $this->execxLocal( - 'merge-base %s %s', + 'merge-base -- %s %s', $child, $parent); $common_ancestor = trim($common_ancestor); @@ -214,7 +214,7 @@ } list($err, $merge_base) = $this->execManualLocal( - 'merge-base %s %s', + 'merge-base -- %s %s', $symbolic_commit, $this->getHeadCommit()); if ($err) { @@ -381,7 +381,7 @@ } list($merge_base) = $this->execxLocal( - 'merge-base %s HEAD', + 'merge-base -- %s HEAD', $default_relative); return trim($merge_base); @@ -569,22 +569,24 @@ } else if ($relative == self::GIT_MAGIC_ROOT_COMMIT) { // First commit. list($stdout) = $this->execxLocal( - 'log --format=medium HEAD'); + 'log --format=medium HEAD --'); } else { // 2..N commits. list($stdout) = $this->execxLocal( - 'log --first-parent --format=medium %s..%s', - $this->getBaseCommit(), - $this->getHeadCommit()); + 'log --first-parent --format=medium %s --', + gitsprintf( + '%s..%s', + $this->getBaseCommit(), + $this->getHeadCommit())); } return $stdout; } public function getGitHistoryLog() { list($stdout) = $this->execxLocal( - 'log --format=medium -n%d %s', + 'log --format=medium -n%d %s --', self::SEARCH_LENGTH_FOR_PARENT_REVISIONS, - $this->getBaseCommit()); + gitsprintf('%s', $this->getBaseCommit())); return $stdout; } @@ -721,7 +723,7 @@ array( 'diff %C --raw %s --', $diff_options, - $diff_base, + gitsprintf('%s', $diff_base), )); $untracked_future = $this->buildLocalFuture( @@ -782,7 +784,7 @@ list($stdout, $stderr) = $this->execxLocal( 'diff %C --raw %s HEAD --', $this->getDiffBaseOptions(), - $this->getBaseCommit()); + gitsprintf('%s', $this->getBaseCommit())); return $this->parseGitRawDiff($stdout); } @@ -935,15 +937,15 @@ public function getChangedFiles($since_commit) { list($stdout) = $this->execxLocal( - 'diff --raw %s', - $since_commit); + 'diff --raw %s --', + gitsprintf('%s', $since_commit)); return $this->parseGitRawDiff($stdout); } public function getBlame($path) { list($stdout) = $this->execxLocal( 'blame --porcelain -w -M %s -- %s', - $this->getBaseCommit(), + gitsprintf('%s', $this->getBaseCommit()), $path); // the --porcelain format prints at least one header line per source line, @@ -1030,7 +1032,7 @@ list($stdout) = $this->execxLocal( 'ls-tree %s -- %s', - $revision, + gitsprintf('%s', $revision), $path); $info = $this->parseGitTree($stdout); @@ -1046,7 +1048,7 @@ } list($stdout) = $this->execxLocal( - 'cat-file blob %s', + 'cat-file blob -- %s', $info[$path]['ref']); return $stdout; } @@ -1171,7 +1173,7 @@ list($message) = $this->execxLocal( 'log -n1 --format=%C %s --', '%s%n%n%b', - $commit); + gitsprintf('%s', $commit)); return $message; } @@ -1249,9 +1251,9 @@ } list($summary) = $this->execxLocal( - 'log -n 1 --format=%C %s', - '%s', - $commit); + 'log -n 1 %s %s --', + '--format=%s', + gitsprintf('%s', $commit)); return trim($summary); } @@ -1268,7 +1270,7 @@ $matches = null; if (preg_match('/^merge-base\((.+)\)$/', $name, $matches)) { list($err, $merge_base) = $this->execManualLocal( - 'merge-base %s HEAD', + 'merge-base -- %s HEAD', $matches[1]); if (!$err) { $this->setBaseCommitExplanation( @@ -1282,7 +1284,7 @@ } } else if (preg_match('/^branch-unique\((.+)\)$/', $name, $matches)) { list($err, $merge_base) = $this->execManualLocal( - 'merge-base %s HEAD', + 'merge-base -- %s HEAD', $matches[1]); if ($err) { return null; @@ -1400,7 +1402,7 @@ if (!$err) { $upstream = rtrim($upstream); list($upstream_merge_base) = $this->execxLocal( - 'merge-base %s HEAD', + 'merge-base -- %s HEAD', $upstream); $upstream_merge_base = rtrim($upstream_merge_base); $this->setBaseCommitExplanation( diff -Nru phabricator-0~git20200925/arcanist/src/repository/api/ArcanistMercurialAPI.php phabricator-0~git20220903/arcanist/src/repository/api/ArcanistMercurialAPI.php --- phabricator-0~git20200925/arcanist/src/repository/api/ArcanistMercurialAPI.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/repository/api/ArcanistMercurialAPI.php 2022-05-17 23:15:03.000000000 +0000 @@ -5,6 +5,13 @@ */ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI { + /** + * Mercurial deceptively indicates that the default encoding is UTF-8 however + * however the actual default appears to be "something else", at least on + * Windows systems. Force all mercurial commands to use UTF-8 encoding. + */ + const ROOT_HG_COMMAND = 'hg --encoding utf-8 '; + private $branch; private $localCommitInfo; private $rawDiffCache = array(); @@ -13,25 +20,24 @@ private $featureFutures = array(); protected function buildLocalFuture(array $argv) { - $env = $this->getMercurialEnvironmentVariables(); + $argv[0] = self::ROOT_HG_COMMAND.$argv[0]; - $argv[0] = 'hg '.$argv[0]; + return $this->newConfiguredFuture(newv('ExecFuture', $argv)); + } - $future = newv('ExecFuture', $argv) - ->setEnv($env) - ->setCWD($this->getPath()); + public function newPassthru($pattern /* , ... */) { + $args = func_get_args(); + $args[0] = self::ROOT_HG_COMMAND.$args[0]; - return $future; + return $this->newConfiguredFuture(newv('PhutilExecPassthru', $args)); } - public function newPassthru($pattern /* , ... */) { + private function newConfiguredFuture(PhutilExecutableFuture $future) { $args = func_get_args(); $env = $this->getMercurialEnvironmentVariables(); - $args[0] = 'hg '.$args[0]; - - return newv('PhutilExecPassthru', $args) + return $future ->setEnv($env) ->setCWD($this->getPath()); } @@ -448,6 +454,10 @@ } } + protected function newCurrentCommitSymbol() { + return $this->getWorkingCopyRevision(); + } + public function getWorkingCopyRevision() { return '.'; } @@ -655,37 +665,117 @@ public function doCommit($message) { $tmp_file = new TempFile(); Filesystem::writeFile($tmp_file, $message); - $this->execxLocal('commit -l %s', $tmp_file); + $this->execxLocal('commit --logfile %s', $tmp_file); $this->reloadWorkingCopy(); } public function amendCommit($message = null) { - if ($message === null) { + $path_statuses = $this->buildUncommittedStatus(); + + $existing_message = $this->getCommitMessage( + $this->getWorkingCopyRevision()); + + if ($message === null || $message == $existing_message) { + if (empty($path_statuses)) { + // If there are no changes to the working directory and the message is + // not being changed then there's nothing to amend. Notably Mercurial + // will return an error code if trying to amend a commit with no change + // to the commit metadata or file changes. + return; + } + $message = $this->getCommitMessage('.'); } $tmp_file = new TempFile(); Filesystem::writeFile($tmp_file, $message); - try { - $this->execxLocal( - 'commit --amend -l %s', - $tmp_file); - } catch (CommandException $ex) { - if (preg_match('/nothing changed/', $ex->getStdout())) { - // NOTE: Mercurial considers it an error to make a no-op amend. Although - // we generally defer to the underlying VCS to dictate behavior, this - // one seems a little goofy, and we use amend as part of various - // workflows under the assumption that no-op amends are fine. If this - // amend failed because it's a no-op, just continue. - } else { + if ($this->getMercurialFeature('evolve')) { + $this->execxLocal('amend --logfile %s --', $tmp_file); + try { + $this->execxLocal('evolve --all --'); + } catch (CommandException $ex) { + $this->execxLocal('evolve --abort --'); throw $ex; } + $this->reloadWorkingCopy(); + return; + } + + // Get the child nodes of the current changeset. + list($children) = $this->execxLocal( + 'log --template %s --rev %s --', + '{node} ', + 'children(.)'); + $child_nodes = array_filter(explode(' ', $children)); + + // For a head commit we can simply use `commit --amend` for both new commit + // message and amending changes from the working directory. + if (empty($child_nodes)) { + $this->execxLocal('commit --amend --logfile %s --', $tmp_file); + } else { + $this->amendNonHeadCommit($child_nodes, $tmp_file); } $this->reloadWorkingCopy(); } + /** + * Amends a non-head commit with a new message and file changes. This + * strategy is for Mercurial repositories without the evolve extension. + * + * 1. Run 'arc-amend' which uses Mercurial internals to amend the current + * commit with updated message/file-changes. It results in a new commit + * from the right parent + * 2. For each branch from the original commit, rebase onto the new commit, + * removing the original branch. Note that there is potential for this to + * cause a conflict but this is something the user has to address. + * 3. Strip the original commit. + * + * @param array The list of child changesets off the original commit. + * @param file The file containing the new commit message. + */ + private function amendNonHeadCommit($child_nodes, $tmp_file) { + list($current) = $this->execxLocal( + 'log --template %s --rev . --', + '{node}'); + + $this->execxLocalWithExtension( + 'arc-hg', + 'arc-amend --logfile %s', + $tmp_file); + + list($new_commit) = $this->execxLocal( + 'log --rev tip --template %s --', + '{node}'); + + try { + $rebase_args = array( + '--dest', + $new_commit, + ); + foreach ($child_nodes as $child) { + $rebase_args[] = '--source'; + $rebase_args[] = $child; + } + + $this->execxLocalWithExtension( + 'rebase', + 'rebase %Ls --', + $rebase_args); + } catch (CommandException $ex) { + $this->execxLocalWithExtension( + 'rebase', + 'rebase --abort --'); + throw $ex; + } + + $this->execxLocalWithExtension( + 'strip', + 'strip --rev %s --', + $current); + } + public function getCommitSummary($commit) { if ($commit == 'null') { return pht('(The Empty Void)'); @@ -957,6 +1047,129 @@ return $this->executeMercurialFeatureTest($feature, true); } + /** + * Returns the necessary flag for using a Mercurial extension. This will + * enable Mercurial built-in extensions and the "arc-hg" extension that is + * included with Arcanist. This will not enable other extensions, e.g. + * "evolve". + * + * @param string The name of the extension to enable. + * @return string A new command pattern that includes the necessary flags to + * enable the specified extension. + */ + private function getMercurialExtensionFlag($extension) { + switch ($extension) { + case 'arc-hg': + $path = phutil_get_library_root('arcanist'); + $path = dirname($path); + $path = $path.'/support/hg/arc-hg.py'; + $ext_config = 'extensions.arc-hg='.$path; + break; + case 'rebase': + $ext_config = 'extensions.rebase='; + break; + case 'shelve': + $ext_config = 'extensions.shelve='; + break; + case 'strip': + $ext_config = 'extensions.strip='; + break; + default: + throw new Exception( + pht('Unknown Mercurial Extension: "%s".', $extension)); + } + + return csprintf('--config %s', $ext_config); + } + + /** + * Produces the arguments that should be passed to Mercurial command + * execution that enables a desired extension. + * + * @param string The name of the extension to enable. + * @param string The command pattern that will be run with the extension + * enabled. + * @param array Parameters for the command pattern argument. + * @return array An array where the first item is a Mercurial command + * pattern that includes the necessary flag for enabling the + * desired extension, and all remaining items are parameters + * to that command pattern. + */ + private function buildMercurialExtensionCommand( + $extension, + $pattern /* , ... */) { + + $args = func_get_args(); + + $pattern_args = array_slice($args, 2); + + $ext_flag = $this->getMercurialExtensionFlag($extension); + + $full_cmd = $ext_flag.' '.$pattern; + + $args = array_merge( + array($full_cmd), + $pattern_args); + + return $args; + } + + public function execxLocalWithExtension( + $extension, + $pattern /* , ... */) { + + $args = func_get_args(); + $extended_args = call_user_func_array( + array($this, 'buildMercurialExtensionCommand'), + $args); + + return call_user_func_array( + array($this, 'execxLocal'), + $extended_args); + } + + public function execFutureLocalWithExtension( + $extension, + $pattern /* , ... */) { + + $args = func_get_args(); + $extended_args = call_user_func_array( + array($this, 'buildMercurialExtensionCommand'), + $args); + + return call_user_func_array( + array($this, 'execFutureLocal'), + $extended_args); + } + + public function execPassthruWithExtension( + $extension, + $pattern /* , ... */) { + + $args = func_get_args(); + $extended_args = call_user_func_array( + array($this, 'buildMercurialExtensionCommand'), + $args); + + return call_user_func_array( + array($this, 'execPassthru'), + $extended_args); + } + + public function execManualLocalWithExtension( + $extension, + $pattern /* , ... */) { + + $args = func_get_args(); + $extended_args = call_user_func_array( + array($this, 'buildMercurialExtensionCommand'), + $args); + + return call_user_func_array( + array($this, 'execManualLocal'), + $extended_args); + } + private function executeMercurialFeatureTest($feature, $resolve) { if (array_key_exists($feature, $this->featureResults)) { return $this->featureResults[$feature]; @@ -982,8 +1195,9 @@ private function newMercurialFeatureFuture($feature) { switch ($feature) { case 'shelve': - return $this->execFutureLocal( - '--config extensions.shelve= shelve --help --'); + return $this->execFutureLocalWithExtension( + 'shelve', + 'shelve --help --'); case 'evolve': return $this->execFutureLocal('prune --help --'); default: @@ -1017,17 +1231,6 @@ return new ArcanistMercurialRepositoryRemoteQuery(); } - public function getMercurialExtensionArguments() { - $path = phutil_get_library_root('arcanist'); - $path = dirname($path); - $path = $path.'/support/hg/arc-hg.py'; - - return array( - '--config', - 'extensions.arc-hg='.$path, - ); - } - protected function newNormalizedURI($uri) { return new ArcanistRepositoryURINormalizer( ArcanistRepositoryURINormalizer::TYPE_MERCURIAL, diff -Nru phabricator-0~git20200925/arcanist/src/repository/graph/query/ArcanistGitCommitGraphQuery.php phabricator-0~git20220903/arcanist/src/repository/graph/query/ArcanistGitCommitGraphQuery.php --- phabricator-0~git20200925/arcanist/src/repository/graph/query/ArcanistGitCommitGraphQuery.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/repository/graph/query/ArcanistGitCommitGraphQuery.php 2022-05-17 23:15:03.000000000 +0000 @@ -84,7 +84,7 @@ $format = implode('%x02', $fields).'%x01'; $future = $api->newFuture( - 'log --format=%s %Ls --stdin', + 'log --format=%s %Ls --stdin --', $format, $flags); $future->write($ref_blob); diff -Nru phabricator-0~git20200925/arcanist/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php phabricator-0~git20220903/arcanist/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php --- phabricator-0~git20200925/arcanist/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php 2022-05-17 23:15:03.000000000 +0000 @@ -19,12 +19,6 @@ // to provide a command which works like "git for-each-ref" locally and // "git ls-remote" when given a remote. - $argv = array(); - foreach ($api->getMercurialExtensionArguments() as $arg) { - $argv[] = $arg; - } - $argv[] = 'arc-ls-markers'; - // NOTE: In remote mode, we're using passthru and a tempfile on this // because it's a remote command and may prompt the user to provide // credentials interactively. In local mode, we can just read stdout. @@ -33,20 +27,17 @@ $tmpfile = new TempFile(); Filesystem::remove($tmpfile); + $argv = array(); $argv[] = '--output'; $argv[] = phutil_string_cast($tmpfile); - } - - $argv[] = '--'; - - if ($remote !== null) { + $argv[] = '--'; $argv[] = $remote->getRemoteName(); - } - if ($remote !== null) { - $passthru = $api->newPassthru('%Ls', $argv); + $err = $api->execPassthruWithExtension( + 'arc-hg', + 'arc-ls-markers %Ls', + $argv); - $err = $passthru->execute(); if ($err) { throw new Exception( pht( @@ -57,8 +48,10 @@ $raw_data = Filesystem::readFile($tmpfile); unset($tmpfile); } else { - $future = $api->newFuture('%Ls', $argv); - list($raw_data) = $future->resolve(); + $future = $api->execFutureLocalWithExtension( + 'arc-hg', + 'arc-ls-markers --'); + list($err, $raw_data) = $future->resolve(); } $items = phutil_json_decode($raw_data); diff -Nru phabricator-0~git20200925/arcanist/src/repository/marker/ArcanistRepositoryMarkerQuery.php phabricator-0~git20220903/arcanist/src/repository/marker/ArcanistRepositoryMarkerQuery.php --- phabricator-0~git20200925/arcanist/src/repository/marker/ArcanistRepositoryMarkerQuery.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/repository/marker/ArcanistRepositoryMarkerQuery.php 2022-05-17 23:15:03.000000000 +0000 @@ -64,8 +64,10 @@ $marker->attachWorkingCopyStateRef($state_ref); $hash = $marker->getCommitHash(); - $hash = $api->getDisplayHash($hash); - $marker->setDisplayHash($hash); + if ($hash !== null) { + $hash = $api->getDisplayHash($hash); + $marker->setDisplayHash($hash); + } } $types = $this->markerTypes; diff -Nru phabricator-0~git20200925/arcanist/src/repository/state/ArcanistMercurialLocalState.php phabricator-0~git20220903/arcanist/src/repository/state/ArcanistMercurialLocalState.php --- phabricator-0~git20200925/arcanist/src/repository/state/ArcanistMercurialLocalState.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/repository/state/ArcanistMercurialLocalState.php 2022-05-17 23:15:03.000000000 +0000 @@ -7,6 +7,14 @@ private $localBranch; private $localBookmark; + public function getLocalCommit() { + return $this->localCommit; + } + + public function getLocalBookmark() { + return $this->localBookmark; + } + protected function executeSaveLocalState() { $api = $this->getRepositoryAPI(); $log = $this->getWorkflow()->getLogEngine(); @@ -152,8 +160,9 @@ 'arc-%s', Filesystem::readRandomCharacters(12)); - $api->execxLocal( - '--config extensions.shelve= shelve --unknown --name %s --', + $api->execxLocalWithExtension( + 'shelve', + 'shelve --unknown --name %s --', $stash_ref); $log->writeStatus( @@ -171,16 +180,18 @@ pht('UNSHELVE'), pht('Restoring uncommitted changes to working copy.')); - $api->execxLocal( - '--config extensions.shelve= unshelve --keep --name %s --', + $api->execxLocalWithExtension( + 'shelve', + 'unshelve --keep --name %s --', $stash_ref); } protected function discardStash($stash_ref) { $api = $this->getRepositoryAPI(); - $api->execxLocal( - '--config extensions.shelve= shelve --delete %s --', + $api->execxLocalWithExtension( + 'shelve', + 'shelve --delete %s --', $stash_ref); } diff -Nru phabricator-0~git20200925/arcanist/src/repository/state/ArcanistRepositoryLocalState.php phabricator-0~git20220903/arcanist/src/repository/state/ArcanistRepositoryLocalState.php --- phabricator-0~git20200925/arcanist/src/repository/state/ArcanistRepositoryLocalState.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/repository/state/ArcanistRepositoryLocalState.php 2022-05-17 23:15:03.000000000 +0000 @@ -192,10 +192,28 @@ return false; } + /** + * Stash uncommitted changes temporarily. Use {@method:restoreStash()} to + * bring these changes back. + * + * Note that saving and restoring changes may not behave as expected if used + * in a non-stack manner, i.e. proper use involves only restoring stashes in + * the reverse order they were saved. + * + * @return wild A reference object that refers to the changes which were + * saved. When restoring changes this should be passed to + * {@method:restoreStash()}. + */ protected function saveStash() { throw new PhutilMethodNotImplementedException(); } + /** + * Restores changes that were previously stashed by {@method:saveStash()}. + * + * @param wild A reference object referring to which previously stashed + * changes to restore, from invoking {@method:saveStash()}. + */ protected function restoreStash($ref) { throw new PhutilMethodNotImplementedException(); } diff -Nru phabricator-0~git20200925/arcanist/src/runtime/ArcanistRuntime.php phabricator-0~git20220903/arcanist/src/runtime/ArcanistRuntime.php --- phabricator-0~git20200925/arcanist/src/runtime/ArcanistRuntime.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/runtime/ArcanistRuntime.php 2022-05-17 23:15:03.000000000 +0000 @@ -270,9 +270,9 @@ $problems[] = sprintf( 'The build of PHP you are running was compiled with the configure '. 'flag "%s", which means it does not support the function "%s()". '. - 'This function is required for Arcanist to run. Install a standard '. - 'build of PHP or rebuild it without this flag. You may also be '. - 'able to build or install the relevant extension separately.', + 'This function is required for this software to run. Install a '. + 'standard build of PHP or rebuild it without this flag. You may '. + 'also be able to build or install the relevant extension separately.', $which, $fname); continue; @@ -477,8 +477,8 @@ $log->writeWarn( pht('VERY META'), pht( - 'You are running one copy of Arcanist (at path "%s") against '. - 'another copy of Arcanist (at path "%s"). Code in the current '. + 'You are running one copy of this software (at path "%s") against '. + 'another copy of this software (at path "%s"). Code in the current '. 'working directory will not be loaded or executed.', $executing_directory, $working_directory)); @@ -519,10 +519,10 @@ if (!isset($toolsets[$binary])) { throw new PhutilArgumentUsageException( pht( - 'Arcanist toolset "%s" is unknown. The Arcanist binary should '. - 'be executed so that "argv[0]" identifies a supported toolset. '. - 'Rename the binary or install the library that provides the '. - 'desired toolset. Current available toolsets: %s.', + 'Toolset "%s" is unknown. The binary should be executed so that '. + '"argv[0]" identifies a supported toolset. Rename the binary or '. + 'install the library that provides the desired toolset. Current '. + 'available toolsets: %s.', $binary, implode(', ', array_keys($toolsets)))); } diff -Nru phabricator-0~git20200925/arcanist/src/serviceprofiler/PhutilServiceProfiler.php phabricator-0~git20220903/arcanist/src/serviceprofiler/PhutilServiceProfiler.php --- phabricator-0~git20200925/arcanist/src/serviceprofiler/PhutilServiceProfiler.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/serviceprofiler/PhutilServiceProfiler.php 2022-05-17 23:15:03.000000000 +0000 @@ -137,7 +137,7 @@ $uri = phutil_censor_credentials($data['uri']); - if (strlen($proxy)) { + if ($proxy !== null) { $desc = "{$proxy} >> {$uri}"; } else { $desc = $uri; @@ -203,6 +203,10 @@ } private static function escapeProfilerStringForDisplay($string) { + if ($string === null) { + return ''; + } + // Convert tabs and newlines to spaces and collapse blocks of whitespace, // most often formatting in queries. $string = preg_replace('/\s{2,}/', ' ', $string); diff -Nru phabricator-0~git20200925/arcanist/src/symbols/PhutilClassMapQuery.php phabricator-0~git20220903/arcanist/src/symbols/PhutilClassMapQuery.php --- phabricator-0~git20200925/arcanist/src/symbols/PhutilClassMapQuery.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/symbols/PhutilClassMapQuery.php 2022-05-17 23:15:03.000000000 +0000 @@ -226,8 +226,8 @@ $unique = $this->uniqueMethod; $sort = $this->sortMethod; - if (strlen($expand)) { - if (!strlen($unique)) { + if ($expand !== null) { + if ($unique === null) { throw new Exception( pht( 'Trying to execute a class map query for descendants of class '. @@ -245,7 +245,7 @@ ->loadObjects(); // Apply the "expand" mechanism, if it is configured. - if (strlen($expand)) { + if ($expand !== null) { $list = array(); foreach ($objects as $object) { foreach (call_user_func(array($object, $expand)) as $instance) { @@ -257,7 +257,7 @@ } // Apply the "unique" mechanism, if it is configured. - if (strlen($unique)) { + if ($unique !== null) { $map = array(); foreach ($list as $object) { $key = call_user_func(array($object, $unique)); @@ -287,12 +287,12 @@ } // Apply the "filter" mechanism, if it is configured. - if (strlen($filter)) { + if ($filter !== null) { $map = mfilter($map, $filter); } // Apply the "sort" mechanism, if it is configured. - if (strlen($sort)) { + if ($sort !== null) { if ($map) { // The "sort" method may return scalars (which we want to sort with // "msort()"), or may return PhutilSortVector objects (which we want diff -Nru phabricator-0~git20200925/arcanist/src/symbols/PhutilSymbolLoader.php phabricator-0~git20220903/arcanist/src/symbols/PhutilSymbolLoader.php --- phabricator-0~git20200925/arcanist/src/symbols/PhutilSymbolLoader.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/symbols/PhutilSymbolLoader.php 2022-05-17 23:15:03.000000000 +0000 @@ -296,11 +296,12 @@ // library without breaking library startup. if ($should_continue) { // We may not have `pht()` yet. - fprintf( - STDERR, + $message = sprintf( "%s: %s\n", 'IGNORING CLASS LOAD FAILURE', $caught->getMessage()); + + @file_put_contents('php://stderr', $message); } else { throw $caught; } diff -Nru phabricator-0~git20200925/arcanist/src/__tests__/PhutilLibraryTestCase.php phabricator-0~git20220903/arcanist/src/__tests__/PhutilLibraryTestCase.php --- phabricator-0~git20200925/arcanist/src/__tests__/PhutilLibraryTestCase.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/__tests__/PhutilLibraryTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -125,8 +125,8 @@ $failures[] = pht( 'Class "%s" implements method "%s" with the wrong visibility. '. 'The method has visibility "%s", but it is defined in parent '. - '"%s" with visibility "%s". In Phabricator, a method which '. - 'overrides another must always have the same visibility.', + '"%s" with visibility "%s". A method which overrides another '. + 'must always have the same visibility.', $class_name, $method_name, $this->getVisibility($method), diff -Nru phabricator-0~git20200925/arcanist/src/toolset/ArcanistArcToolset.php phabricator-0~git20220903/arcanist/src/toolset/ArcanistArcToolset.php --- phabricator-0~git20200925/arcanist/src/toolset/ArcanistArcToolset.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/toolset/ArcanistArcToolset.php 2022-05-17 23:15:03.000000000 +0000 @@ -9,7 +9,7 @@ array( 'name' => 'conduit-uri', 'param' => 'uri', - 'help' => pht('Connect to Phabricator install specified by __uri__.'), + 'help' => pht('Connect to server specified by __uri__.'), ), array( 'name' => 'conduit-token', diff -Nru phabricator-0~git20200925/arcanist/src/toolset/ArcanistPrompt.php phabricator-0~git20220903/arcanist/src/toolset/ArcanistPrompt.php --- phabricator-0~git20200925/arcanist/src/toolset/ArcanistPrompt.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/toolset/ArcanistPrompt.php 2022-05-17 23:15:03.000000000 +0000 @@ -93,16 +93,9 @@ // NOTE: We're making stdin nonblocking so that we can respond to signals // immediately. If we don't, and you ^C during a prompt, the program does - // not handle the signal until fgets() returns. + // not handle the signal until fgets() returns. See also T13649. - // On Windows, we skip this because stdin can not be made nonblocking. - - if (!phutil_is_windows()) { - $ok = stream_set_blocking($stdin, false); - if (!$ok) { - throw new Exception(pht('Unable to set stdin nonblocking.')); - } - } + $guard = ArcanistNonblockingGuard::newForStream($stdin); echo "\n"; @@ -123,7 +116,7 @@ $is_saved = false; - if (phutil_is_windows()) { + if (!$guard->getIsNonblocking()) { $response = fgets($stdin); } else { while (true) { diff -Nru phabricator-0~git20200925/arcanist/src/toolset/workflow/ArcanistShellCompleteWorkflow.php phabricator-0~git20220903/arcanist/src/toolset/workflow/ArcanistShellCompleteWorkflow.php --- phabricator-0~git20200925/arcanist/src/toolset/workflow/ArcanistShellCompleteWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/toolset/workflow/ArcanistShellCompleteWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -14,7 +14,7 @@ public function getWorkflowInformation() { $help = pht(<<, ...)" for test case "%s" '. + 'passed bad value for test result. Expected null, Exception, '. + 'or Throwable; got: %s.', + $message, + phutil_describe_type($actual)); + } else { + $output = pht( + 'Call to "assertCaught(..., , ...)" passed bad value for '. + 'test result. Expected null, Exception, or Throwable; got: %s.', + phutil_describe_type($actual)); + } + + $this->failTest($output); + + throw new PhutilTestTerminatedException($output); + } + + $expect_list = null; + + if ($expect === false) { + $expect_list = array(); + } else if ($expect === true) { + $expect_list = array( + 'Exception', + 'Throwable', + ); + } else if (is_string($expect) || is_array($expect)) { + $list = (array)$expect; + + $items_ok = true; + foreach ($list as $key => $item) { + if (!phutil_nonempty_stringlike($item)) { + $items_ok = false; + break; + } + + $list[$key] = phutil_string_cast($item); + } + + if ($items_ok) { + $expect_list = $list; + } + } + + if ($expect_list === null) { + if ($message !== null) { + $output = pht( + 'Call to "assertCaught(, ...)" for test case "%s" '. + 'passed bad expected value. Expected bool, class name as a string, '. + 'or a list of class names. Got: %s.', + $message, + phutil_describe_type($expect)); + } else { + $output = pht( + 'Call to "assertCaught(, ...)" passed bad expected value. '. + 'expected result. Expected null, Exception, or Throwable; got: %s.', + phutil_describe_type($expect)); + } + + $this->failTest($output); + + throw new PhutilTestTerminatedException($output); + } + + if ($actual === null) { + $is_match = !$expect_list; + } else { + $is_match = false; + foreach ($expect_list as $exception_class) { + if ($actual instanceof $exception_class) { + $is_match = true; + break; + } + } + } + + if ($is_match) { + $this->assertions++; + return; + } + + $caller = self::getCallerInfo(); + $file = $caller['file']; + $line = $caller['line']; + + $output = array(); + + if ($message !== null) { + $output[] = pht( + 'Assertion of caught exception failed (at %s:%d in test case "%s").', + $file, + $line, + $message); + } else { + $output[] = pht( + 'Assertion of caught exception failed (at %s:%d).', + $file, + $line); + } + + if ($actual === null) { + $output[] = pht('Expected any exception, got no exception.'); + } else if (!$expect_list) { + $output[] = pht( + 'Expected no exception, got exception of class "%s".', + get_class($actual)); + } else { + $expected_classes = implode(', ', $expect_list); + $output[] = pht( + 'Expected exception (in class(es): %s), got exception of class "%s".', + $expected_classes, + get_class($actual)); + } + + $output = implode("\n\n", $output); + + $this->failTest($output); + + throw new PhutilTestTerminatedException($output); + } + /* -( Exception Handling )------------------------------------------------- */ @@ -408,7 +549,7 @@ * * @task internal */ - final private function failTest($reason) { + private function failTest($reason) { $this->resultTest(ArcanistUnitTestResult::RESULT_FAIL, $reason); } @@ -421,7 +562,7 @@ * * @task internal */ - final private function passTest($reason) { + private function passTest($reason) { $this->resultTest(ArcanistUnitTestResult::RESULT_PASS, $reason); } @@ -433,12 +574,12 @@ * @return void * @task internal */ - final private function skipTest($reason) { + private function skipTest($reason) { $this->resultTest(ArcanistUnitTestResult::RESULT_SKIP, $reason); } - final private function resultTest($test_result, $reason) { + private function resultTest($test_result, $reason) { $coverage = $this->endCoverage(); $result = new ArcanistUnitTestResult(); @@ -553,7 +694,7 @@ /** * @phutil-external-symbol function xdebug_start_code_coverage */ - final private function beginCoverage() { + private function beginCoverage() { if (!$this->enableCoverage) { return; } @@ -566,7 +707,7 @@ * @phutil-external-symbol function xdebug_get_code_coverage * @phutil-external-symbol function xdebug_stop_code_coverage */ - final private function endCoverage() { + private function endCoverage() { if (!$this->enableCoverage) { return; } @@ -618,7 +759,7 @@ return $coverage; } - final private function assertCoverageAvailable() { + private function assertCoverageAvailable() { if (!function_exists('xdebug_start_code_coverage')) { throw new Exception( pht("You've enabled code coverage but XDebug is not installed.")); @@ -675,7 +816,7 @@ * * @return map */ - final private static function getCallerInfo() { + private static function getCallerInfo() { $callee = array(); $caller = array(); $seen = false; diff -Nru phabricator-0~git20200925/arcanist/src/unit/engine/PhutilUnitTestEngine.php phabricator-0~git20220903/arcanist/src/unit/engine/PhutilUnitTestEngine.php --- phabricator-0~git20200925/arcanist/src/unit/engine/PhutilUnitTestEngine.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/unit/engine/PhutilUnitTestEngine.php 2022-05-17 23:15:03.000000000 +0000 @@ -170,16 +170,14 @@ if (!$library_name) { throw new Exception( pht( - "Attempting to run unit tests on a libphutil library which has ". + "Attempting to run unit tests on a library which has ". "not been loaded, at:\n\n". " %s\n\n". - "This probably means one of two things:\n\n". - " - You may need to add this library to %s.\n". - " - You may be running tests on a copy of libphutil or ". - "arcanist using a different copy of libphutil or arcanist. ". - "This operation is not supported.\n", - $library_root, - '.arcconfig.')); + "Make sure this library is configured to load.\n\n". + "(In rare cases, this may be because you are attempting to run ". + "one copy of this software against a different copy of this ". + "software. This operation is not supported.)", + $library_root)); } $path = Filesystem::resolvePath($path, $root); diff -Nru phabricator-0~git20200925/arcanist/src/unit/renderer/ArcanistUnitConsoleRenderer.php phabricator-0~git20220903/arcanist/src/unit/renderer/ArcanistUnitConsoleRenderer.php --- phabricator-0~git20200925/arcanist/src/unit/renderer/ArcanistUnitConsoleRenderer.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/unit/renderer/ArcanistUnitConsoleRenderer.php 2022-05-17 23:15:03.000000000 +0000 @@ -65,9 +65,10 @@ 50 => "%s{$star} ", 200 => '%s ', 500 => '%s ', - INF => '%s ', ); + $least_acceptable = '%s '; + $milliseconds = $seconds * 1000; $duration = $this->formatTime($seconds); foreach ($acceptableness as $upper_bound => $formatting) { @@ -75,7 +76,8 @@ return phutil_console_format($formatting, $duration); } } - return phutil_console_format(end($acceptableness), $duration); + + return phutil_console_format($least_acceptable, $duration); } private function formatTime($seconds) { diff -Nru phabricator-0~git20200925/arcanist/src/upload/ArcanistFileUploader.php phabricator-0~git20220903/arcanist/src/upload/ArcanistFileUploader.php --- phabricator-0~git20200925/arcanist/src/upload/ArcanistFileUploader.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/upload/ArcanistFileUploader.php 2022-05-17 23:15:03.000000000 +0000 @@ -313,7 +313,7 @@ * @task internal */ private function writeStatus($message) { - fwrite(STDERR, $message."\n"); + PhutilSystem::writeStderr($message."\n"); } } diff -Nru phabricator-0~git20200925/arcanist/src/utils/AbstractDirectedGraph.php phabricator-0~git20220903/arcanist/src/utils/AbstractDirectedGraph.php --- phabricator-0~git20200925/arcanist/src/utils/AbstractDirectedGraph.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/AbstractDirectedGraph.php 2022-05-17 23:15:03.000000000 +0000 @@ -318,7 +318,7 @@ * which cycle. * @task cycle */ - final private function performCycleDetection($node, array $visited) { + private function performCycleDetection($node, array $visited) { $visited[$node] = true; foreach ($this->knownNodes[$node] as $edge) { if (isset($visited[$edge])) { diff -Nru phabricator-0~git20200925/arcanist/src/utils/ArcanistNonblockingGuard.php phabricator-0~git20220903/arcanist/src/utils/ArcanistNonblockingGuard.php --- phabricator-0~git20200925/arcanist/src/utils/ArcanistNonblockingGuard.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/ArcanistNonblockingGuard.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,56 @@ +stream = $stream; + + if (phutil_is_windows()) { + + // On Windows, we skip this because stdin can not be made nonblocking. + + } else if (!function_exists('pcntl_signal')) { + + // If we can't handle signals, we: can't reset the flag if we're + // interrupted; but also don't benefit from setting it in the first + // place since it's only relevant for handling interrupts during + // prompts. So just skip this. + + } else { + + // See T13649. Note that the "blocked" key identifies whether the + // stream is blocking or nonblocking, not whether it will block when + // read or written. + + $metadata = stream_get_meta_data($stream); + $is_blocking = idx($metadata, 'blocked'); + if ($is_blocking) { + $ok = stream_set_blocking($stream, false); + if (!$ok) { + throw new Exception(pht('Unable to set stream nonblocking.')); + } + $guard->didSetNonblocking = true; + } + } + + return $guard; + } + + public function getIsNonblocking() { + return $this->didSetNonblocking; + } + + public function __destruct() { + if ($this->stream && $this->didSetNonblocking) { + stream_set_blocking($this->stream, true); + } + + $this->stream = null; + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/utils/PhutilArray.php phabricator-0~git20220903/arcanist/src/utils/PhutilArray.php --- phabricator-0~git20200925/arcanist/src/utils/PhutilArray.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/PhutilArray.php 2022-05-17 23:15:03.000000000 +0000 @@ -29,6 +29,7 @@ /* -( Countable Interface )------------------------------------------------ */ + #[\ReturnTypeWillChange] public function count() { return count($this->data); } @@ -37,22 +38,27 @@ /* -( Iterator Interface )------------------------------------------------- */ + #[\ReturnTypeWillChange] public function current() { return current($this->data); } + #[\ReturnTypeWillChange] public function key() { return key($this->data); } + #[\ReturnTypeWillChange] public function next() { return next($this->data); } + #[\ReturnTypeWillChange] public function rewind() { reset($this->data); } + #[\ReturnTypeWillChange] public function valid() { return (key($this->data) !== null); } @@ -61,18 +67,22 @@ /* -( ArrayAccess Interface )---------------------------------------------- */ + #[\ReturnTypeWillChange] public function offsetExists($key) { return array_key_exists($key, $this->data); } + #[\ReturnTypeWillChange] public function offsetGet($key) { return $this->data[$key]; } + #[\ReturnTypeWillChange] public function offsetSet($key, $value) { $this->data[$key] = $value; } + #[\ReturnTypeWillChange] public function offsetUnset($key) { unset($this->data[$key]); } diff -Nru phabricator-0~git20200925/arcanist/src/utils/PhutilCallbackFilterIterator.php phabricator-0~git20220903/arcanist/src/utils/PhutilCallbackFilterIterator.php --- phabricator-0~git20200925/arcanist/src/utils/PhutilCallbackFilterIterator.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/PhutilCallbackFilterIterator.php 2022-05-17 23:15:03.000000000 +0000 @@ -18,6 +18,7 @@ $this->callback = $callback; } + #[\ReturnTypeWillChange] public function accept() { return call_user_func($this->callback, $this->current()); } diff -Nru phabricator-0~git20200925/arcanist/src/utils/PhutilSystem.php phabricator-0~git20220903/arcanist/src/utils/PhutilSystem.php --- phabricator-0~git20200925/arcanist/src/utils/PhutilSystem.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/PhutilSystem.php 2022-05-17 23:15:03.000000000 +0000 @@ -3,10 +3,73 @@ /** * Interact with the operating system. * + * @task stdio Interacting with Standard I/O * @task memory Interacting with System Memory */ final class PhutilSystem extends Phobject { + private static $stdin = false; + private static $stderr = false; + private static $stdout = false; + + /** + * @task stdio + */ + public static function getStdinHandle() { + if (self::$stdin === false) { + self::$stdin = self::getStdioHandle('STDIN'); + } + + return self::$stdin; + } + + /** + * @task stdio + */ + public static function getStdoutHandle() { + if (self::$stdout === false) { + self::$stdout = self::getStdioHandle('STDOUT'); + } + + return self::$stdout; + } + + /** + * @task stdio + */ + public static function getStderrHandle() { + if (self::$stderr === false) { + self::$stderr = self::getStdioHandle('STDERR'); + } + + return self::$stderr; + } + + /** + * @task stdio + */ + public static function writeStderr($message) { + $stderr = self::getStderrHandle(); + + if ($stderr === null) { + return; + } + + $message = phutil_string_cast($message); + @fwrite($stderr, $message); + } + + + /** + * @task stdio + */ + private static function getStdioHandle($ref) { + if (defined($ref)) { + return constant($ref); + } + + return null; + } /** * Get information about total and free memory on the system. diff -Nru phabricator-0~git20200925/arcanist/src/utils/__tests__/PhutilUTF8TestCase.php phabricator-0~git20220903/arcanist/src/utils/__tests__/PhutilUTF8TestCase.php --- phabricator-0~git20200925/arcanist/src/utils/__tests__/PhutilUTF8TestCase.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/__tests__/PhutilUTF8TestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -498,6 +498,8 @@ phutil_utf8_convert('xyz', 'moon language', 'UTF-8'); } catch (Exception $ex) { $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; } $this->assertTrue((bool)$caught, pht('Conversion with bogus encoding.')); diff -Nru phabricator-0~git20200925/arcanist/src/utils/__tests__/PhutilUtilsTestCase.php phabricator-0~git20220903/arcanist/src/utils/__tests__/PhutilUtilsTestCase.php --- phabricator-0~git20200925/arcanist/src/utils/__tests__/PhutilUtilsTestCase.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/__tests__/PhutilUtilsTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -1000,4 +1000,74 @@ } } + public function testEmptyStringMethods() { + + $uri = new PhutilURI('http://example.org/'); + + $map = array( + array(null, false, false, false, 'literal null'), + array('', false, false, false, 'empty string'), + array('x', true, true, true, 'nonempty string'), + array(false, null, null, null, 'bool'), + array(1, null, null, true, 'integer'), + array($uri, null, true, true, 'uri object'), + array(2.5, null, null, true, 'float'), + array(array(), null, null, null, 'array'), + array((object)array(), null, null, null, 'object'), + ); + + foreach ($map as $test_case) { + $input = $test_case[0]; + + $expect_string = $test_case[1]; + $expect_stringlike = $test_case[2]; + $expect_scalar = $test_case[3]; + + $test_name = $test_case[4]; + + $this->executeEmptyStringTest( + $input, + $expect_string, + 'phutil_nonempty_string', + $test_name); + + $this->executeEmptyStringTest( + $input, + $expect_stringlike, + 'phutil_nonempty_stringlike', + $test_name); + + $this->executeEmptyStringTest( + $input, + $expect_scalar, + 'phutil_nonempty_scalar', + $test_name); + } + + } + + private function executeEmptyStringTest($input, $expect, $call, $name) { + $name = sprintf('%s(<%s>)', $call, $name); + + $caught = null; + try { + $actual = call_user_func($call, $input); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + if ($expect === null) { + $expect_exceptions = array('InvalidArgumentException'); + } else { + $expect_exceptions = false; + } + + $this->assertCaught($expect_exceptions, $caught, $name); + if (!$caught) { + $this->assertEqual($expect, $actual, $name); + } + } + } diff -Nru phabricator-0~git20200925/arcanist/src/utils/utf8.php phabricator-0~git20220903/arcanist/src/utils/utf8.php --- phabricator-0~git20200925/arcanist/src/utils/utf8.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/utf8.php 2022-05-17 23:15:03.000000000 +0000 @@ -314,6 +314,8 @@ * @return int The console display length of the string. */ function phutil_utf8_console_strlen($string) { + $string = phutil_string_cast($string); + // Formatting and colors don't contribute any width in the console. $string = preg_replace("/\x1B\[\d*m/", '', $string); @@ -426,6 +428,8 @@ * @return list A list of characters in the string. */ function phutil_utf8v($string, $byte_limit = null) { + $string = phutil_string_cast($string); + $res = array(); $len = strlen($string); diff -Nru phabricator-0~git20200925/arcanist/src/utils/utils.php phabricator-0~git20220903/arcanist/src/utils/utils.php --- phabricator-0~git20200925/arcanist/src/utils/utils.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/utils.php 2022-05-17 23:15:03.000000000 +0000 @@ -876,14 +876,19 @@ if (!is_array($item)) { throw new InvalidArgumentException( pht( - 'Expected all items passed to `%s` to be arrays, but '. + 'Expected all items passed to "array_mergev()" to be arrays, but '. 'argument with key "%s" has type "%s".', - __FUNCTION__.'()', $key, gettype($item))); } } + // See T13588. In PHP8, "call_user_func_array()" will attempt to use + // "unnatural" array keys as named parameters, and then fail because + // "array_merge()" does not accept named parameters . Guarantee the list is + // a "natural" list to avoid this. + $arrayv = array_values($arrayv); + return call_user_func_array('array_merge', $arrayv); } @@ -2003,3 +2008,214 @@ return $partitions; } + +function phutil_preg_match( + $pattern, + $subject, + $flags = 0, + $offset = 0) { + + $matches = null; + $result = @preg_match($pattern, $subject, $matches, $flags, $offset); + if ($result === false || $result === null) { + phutil_raise_preg_exception( + 'preg_match', + array( + $pattern, + $subject, + $matches, + $flags, + $offset, + )); + } + + return $matches; +} + +function phutil_preg_match_all( + $pattern, + $subject, + $flags = 0, + $offset = 0) { + + $matches = null; + $result = @preg_match_all($pattern, $subject, $matches, $flags, $offset); + if ($result === false || $result === null) { + phutil_raise_preg_exception( + 'preg_match_all', + array( + $pattern, + $subject, + $matches, + $flags, + $offset, + )); + } + + return $matches; +} + +function phutil_raise_preg_exception($function, array $argv) { + $trap = new PhutilErrorTrap(); + + // NOTE: This ugly construction to avoid issues with reference behavior when + // passing values through "call_user_func_array()". + + switch ($function) { + case 'preg_match': + @preg_match($argv[0], $argv[1], $argv[2], $argv[3], $argv[4]); + break; + case 'preg_match_all': + @preg_match_all($argv[0], $argv[1], $argv[2], $argv[3], $argv[4]); + break; + } + $error_message = $trap->getErrorsAsString(); + + $trap->destroy(); + + $pattern = $argv[0]; + $pattern_display = sprintf( + '"%s"', + addcslashes($pattern, '\\\"')); + + $message = array(); + $message[] = pht( + 'Call to %s(%s, ...) failed.', + $function, + $pattern_display); + + if (strlen($error_message)) { + $message[] = pht( + 'Regular expression engine emitted message: %s', + $error_message); + } + + $message = implode("\n\n", $message); + + throw new PhutilRegexException($message); +} + + +/** + * Test if a value is a nonempty string. + * + * The value "null" and the empty string are considered empty; all other + * strings are considered nonempty. + * + * This method raises an exception if passed a value which is neither null + * nor a string. + * + * @param Value to test. + * @return bool True if the parameter is a nonempty string. + */ +function phutil_nonempty_string($value) { + if ($value === null) { + return false; + } + + if ($value === '') { + return false; + } + + if (is_string($value)) { + return true; + } + + throw new InvalidArgumentException( + pht( + 'Call to phutil_nonempty_string() expected null or a string, got: %s.', + phutil_describe_type($value))); +} + + +/** + * Test if a value is a nonempty, stringlike value. + * + * The value "null", the empty string, and objects which have a "__toString()" + * method which returns the empty string are empty. + * + * Other strings, and objects with a "__toString()" method that returns a + * string other than the empty string are considered nonempty. + * + * This method raises an exception if passed any other value. + * + * @param Value to test. + * @return bool True if the parameter is a nonempty, stringlike value. + */ +function phutil_nonempty_stringlike($value) { + if ($value === null) { + return false; + } + + if ($value === '') { + return false; + } + + if (is_string($value)) { + return true; + } + + if (is_object($value)) { + try { + $string = phutil_string_cast($value); + return phutil_nonempty_string($string); + } catch (Exception $ex) { + // Continue below. + } catch (Throwable $ex) { + // Continue below. + } + } + + throw new InvalidArgumentException( + pht( + 'Call to phutil_nonempty_stringlike() expected a string or stringlike '. + 'object, got: %s.', + phutil_describe_type($value))); +} + + +/** + * Test if a value is a nonempty, scalar value. + * + * The value "null", the empty string, and objects which have a "__toString()" + * method which returns the empty string are empty. + * + * Other strings, objects with a "__toString()" method which returns a + * string other than the empty string, integers, and floats are considered + * scalar. + * + * This method raises an exception if passed any other value. + * + * @param Value to test. + * @return bool True if the parameter is a nonempty, scalar value. + */ +function phutil_nonempty_scalar($value) { + if ($value === null) { + return false; + } + + if ($value === '') { + return false; + } + + if (is_string($value) || is_int($value) || is_float($value)) { + return true; + } + + if (is_object($value)) { + try { + $string = phutil_string_cast($value); + return phutil_nonempty_string($string); + } catch (Exception $ex) { + // Continue below. + } catch (Throwable $ex) { + // Continue below. + } + } + + throw new InvalidArgumentException( + pht( + 'Call to phutil_nonempty_scalar() expected: a string; or stringlike '. + 'object; or int; or float. Got: %s.', + phutil_describe_type($value))); +} diff -Nru phabricator-0~git20200925/arcanist/src/utils/viewutils.php phabricator-0~git20220903/arcanist/src/utils/viewutils.php --- phabricator-0~git20200925/arcanist/src/utils/viewutils.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/utils/viewutils.php 2022-05-17 23:15:03.000000000 +0000 @@ -141,7 +141,7 @@ $scale = array_shift($scales); $label = array_shift($labels); while ($n >= $scale && count($labels)) { - $remainder += ($n % $scale) * $accum; + $remainder += ((int)$n % $scale) * $accum; $n /= $scale; $accum *= $scale; $label = array_shift($labels); diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistAmendWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistAmendWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistAmendWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistAmendWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -164,8 +164,6 @@ ->execute(); } - return; - if ($api->getUncommittedChanges()) { // TODO: Make this class of error show the uncommitted changes. diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistCallConduitWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistCallConduitWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistCallConduitWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistCallConduitWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -15,8 +15,7 @@ - Call parameters are required, and read as a JSON blob from stdin. - Results are written to stdout as a JSON blob. -This workflow is primarily useful for writing scripts which integrate -with Phabricator. Examples: +This workflow is primarily useful for writing scripts. Examples: $ echo '{}' | arc call-conduit -- conduit.ping $ echo '{"phid":"PHID-FILE-xxxx"}' | arc call-conduit -- file.download diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistDiffWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistDiffWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistDiffWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistDiffWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -115,8 +115,7 @@ 'raw' => array( 'help' => pht( 'Read diff from stdin, not from the working copy. This disables '. - 'many Arcanist/Phabricator features which depend on having access '. - 'to the working copy.'), + 'many features which depend on having access to the working copy.'), 'conflicts' => array( 'apply-patches' => pht('%s disables lint.', '--raw'), 'never-apply-patches' => pht('%s disables lint.', '--raw'), @@ -138,8 +137,8 @@ 'param' => 'command', 'help' => pht( 'Generate diff by executing a specified command, not from the '. - 'working copy. This disables many Arcanist/Phabricator features '. - 'which depend on having access to the working copy.'), + 'working copy. This disables many features which depend on having '. + 'access to the working copy.'), 'conflicts' => array( 'apply-patches' => pht('%s disables lint.', '--raw-command'), 'never-apply-patches' => pht('%s disables lint.', '--raw-command'), @@ -326,9 +325,8 @@ 'head' => array( 'param' => 'commit', 'help' => pht( - 'Specify the end of the commit range. This disables many '. - 'Arcanist/Phabricator features which depend on having access to '. - 'the working copy.'), + 'Specify the end of the commit range. This disables many features '. + 'which depend on having access to the working copy.'), 'supports' => array('git'), 'nosupport' => array( 'svn' => pht('Subversion does not support commit ranges.'), @@ -517,7 +515,7 @@ if ($is_draft) { throw new ArcanistUsageException( pht( - 'You have specified "--draft", but the version of Phabricator '. + 'You have specified "--draft", but the software version '. 'on the server is too old to support draft revisions. Omit '. 'the flag or upgrade the server software.')); } @@ -674,6 +672,8 @@ if ($should_edit) { $edited = $this->newInteractiveEditor($remote_corpus) ->setName('differential-edit-revision-info') + ->setTaskMessage(pht( + 'Update the details for a revision, then save and exit.')) ->editInteractively(); if ($edited != $remote_corpus) { $remote_corpus = $edited; @@ -699,7 +699,7 @@ $this->revisionID = $revision_id; $revision['message'] = $this->getArgument('message'); - if (!strlen($revision['message'])) { + if ($revision['message'] === null) { $update_messages = $this->readScratchJSONFile('update-messages.json'); $update_messages[$revision_id] = $this->getUpdateMessage( @@ -806,7 +806,10 @@ if ($is_raw) { if ($this->getArgument('raw')) { - fwrite(STDERR, pht('Reading diff from stdin...')."\n"); + PhutilSystem::writeStderr( + tsprintf( + "%s\n", + pht('Reading diff from stdin...'))); $raw_diff = file_get_contents('php://stdin'); } else if ($this->getArgument('raw-command')) { list($raw_diff) = execx('%C', $this->getArgument('raw-command')); @@ -947,7 +950,7 @@ } catch (ConduitClientException $e) { if ($e->getErrorCode() == 'ERR-BAD-ARCANIST-PROJECT') { echo phutil_console_wrap( - pht('Lookup of encoding in arcanist project failed: %s', + pht('Lookup of encoding in project failed: %s', $e->getMessage())."\n"); } else { throw $e; @@ -988,10 +991,10 @@ 'these files will be marked as binary.', phutil_count($utf8_problems)), pht( - "You can learn more about how Phabricator handles character ". + "You can learn more about how this software handles character ". "encodings (and how to configure encoding settings and detect and ". "correct encoding problems) by reading 'User Guide: UTF-8 and ". - "Character Encoding' in the Phabricator documentation."), + "Character Encoding' in the documentation."), pht( '%s AFFECTED FILE(S)', phutil_count($utf8_problems))); @@ -1476,6 +1479,8 @@ } else { $new_template = $this->newInteractiveEditor($template) ->setName('new-commit') + ->setTaskMessage(pht( + 'Provide the details for a new revision, then save and exit.')) ->editInteractively(); } $first = false; @@ -1736,9 +1741,12 @@ if ($template == '') { $comments = $this->getDefaultUpdateMessage(); + $comments = phutil_string_cast($comments); + $comments = rtrim($comments); + $template = sprintf( "%s\n\n# %s\n#\n# %s\n# %s\n#\n# %s\n# $ %s\n\n", - rtrim($comments), + $comments, pht( 'Updating %s: %s', "D{$fields['revisionID']}", @@ -1752,6 +1760,8 @@ $comments = $this->newInteractiveEditor($template) ->setName('differential-update-comments') + ->setTaskMessage(pht( + 'Update the revision comments, then save and exit.')) ->editInteractively(); return $comments; @@ -2354,7 +2364,7 @@ if (strlen($branch)) { $upstream_path = $api->getPathToUpstream($branch); $remote_branch = $upstream_path->getRemoteBranchName(); - if (strlen($remote_branch)) { + if ($remote_branch !== null) { return array( array( 'type' => 'branch', @@ -2368,7 +2378,7 @@ // If "arc.land.onto.default" is configured, use that. $config_key = 'arc.land.onto.default'; $onto = $this->getConfigFromAnySource($config_key); - if (strlen($onto)) { + if ($onto !== null) { return array( array( 'type' => 'branch', @@ -2643,7 +2653,7 @@ if (!$supported) { $this->writeInfo( pht('SKIP STAGING'), - pht('Phabricator does not support staging areas for this repository.')); + pht('The server does not support staging areas for this repository.')); return self::STAGING_REPOSITORY_UNSUPPORTED; } @@ -2741,6 +2751,17 @@ 'git push -- %s %s', $staging_uri, $ref); + + if ($err) { + $this->writeWarn( + pht('STAGING FAILED'), + pht('Unable to push lfs changes to the staging area.')); + + throw new ArcanistUsageException( + pht( + 'Failed to push lfs changes to staging area. Correct the issue, '. + 'or use --skip-staging to skip this step.')); + } } return $refs; diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistInstallCertificateWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistInstallCertificateWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistInstallCertificateWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistInstallCertificateWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -19,12 +19,12 @@ public function getCommandHelp() { return phutil_console_format(<<getProtocol(); diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistLiberateWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistLiberateWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistLiberateWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistLiberateWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -11,13 +11,13 @@ // TOOLSETS: Expand this help. $help = pht(<<newWorkflowInformation() ->setSynopsis( - pht('Create or update an Arcanist library.')) + pht('Create or update a library.')) ->addExample(pht('**liberate**')) ->addExample(pht('**liberate** [__path__]')) ->setHelp($help); @@ -79,22 +79,35 @@ ); } + $any_errors = false; foreach ($paths as $path) { $log->writeStatus( pht('WORK'), pht( 'Updating library: %s', Filesystem::readablePath($path).DIRECTORY_SEPARATOR)); - $this->liberatePath($path); + $exit_code = $this->liberatePath($path); + if ($exit_code !== 0) { + $any_errors = true; + $log->writeError( + pht('ERROR'), + pht('Failed to update library: %s', $path)); + } } - $log->writeSuccess( - pht('DONE'), - pht('Updated %s librarie(s).', phutil_count($paths))); + if (!$any_errors) { + $log->writeSuccess( + pht('DONE'), + pht('Updated %s librarie(s).', phutil_count($paths))); + } return 0; } + /** + * @return int The exit code of running the rebuild-map.php script, which + * will be 0 to indicate success or non-zero for failure. + */ private function liberatePath($path) { if (!Filesystem::pathExists($path.'/__phutil_library_init__.php')) { echo tsprintf( @@ -103,8 +116,7 @@ 'No library currently exists at the path "%s"...', $path)); $this->liberateCreateDirectory($path); - $this->liberateCreateLibrary($path); - return; + return $this->liberateCreateLibrary($path); } $version = $this->getLibraryFormatVersion($path); @@ -119,8 +131,6 @@ throw new ArcanistUsageException( pht("Unknown library version '%s'!", $version)); } - - echo tsprintf("%s\n", pht('Done.')); } private function getLibraryFormatVersion($path) { @@ -140,6 +150,10 @@ return 1; } + /** + * @return int The exit code of running the rebuild-map.php script, which + * will be 0 to indicate success or non-zero for failure. + */ private function liberateVersion2($path) { $bin = $this->getScriptPath('support/lib/rebuild-map.php'); @@ -181,10 +195,14 @@ execx('mkdir -p %R', $path); } + /** + * @return int The exit code of running the rebuild-map.php script, which + * will be 0 to indicate success or non-zero for failure. + */ private function liberateCreateLibrary($path) { $init_path = $path.'/__phutil_library_init__.php'; if (Filesystem::pathExists($init_path)) { - return; + return 0; } echo pht("Creating new libphutil library in '%s'.", $path)."\n"; @@ -213,7 +231,7 @@ '__phutil_library_init__.php', $path); Filesystem::writeFile($init_path, $template); - $this->liberateVersion2($path); + return $this->liberateVersion2($path); } diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistPasteWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistPasteWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistPasteWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistPasteWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -12,7 +12,7 @@ Share and grab text using the Paste application. To create a paste, use the "--input" flag or provide the text on stdin: - $ cat list_of_ducks.txt | arc paste + $ cat list_of_ducks.txt | arc paste -- $ arc paste --input list_of_ducks.txt To retrieve a paste, specify the paste ID: diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistPatchWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistPatchWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistPatchWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistPatchWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -707,7 +707,7 @@ 'git apply --whitespace nowarn --index --reject -- %s', $patchfile); $passthru->setCWD($repository_api->getPath()); - $err = $passthru->execute(); + $err = $passthru->resolve(); if ($err) { echo phutil_console_format( @@ -890,8 +890,8 @@ 'revision_id' => $revision_id, )); $prompt_message = pht( - ' Note arcanist failed to load the commit message '. - 'from differential for revision %s.', + ' NOTE: Failed to load the commit message from Differential (for '. + 'revision "%s".)', "D{$revision_id}"); } @@ -909,6 +909,8 @@ $commit_message = $this->newInteractiveEditor($template) ->setName('arcanist-patch-commit-message') + ->setTaskMessage(pht( + 'Supply a commit message for this patch, then save and exit.')) ->editInteractively(); $commit_message = ArcanistCommentRemover::removeComments($commit_message); diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistUpgradeWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistUpgradeWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistUpgradeWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistUpgradeWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -9,12 +9,12 @@ public function getWorkflowInformation() { $help = pht(<<newWorkflowInformation() - ->setSynopsis(pht('Upgrade Arcanist to the latest version.')) + ->setSynopsis(pht('Upgrade this program to the latest version.')) ->addExample(pht('**upgrade**')) ->setHelp($help); } @@ -51,10 +51,10 @@ if (!$is_git) { throw new PhutilArgumentUsageException( pht( - 'The "arc upgrade" workflow uses "git pull" to upgrade '. - 'Arcanist, but the "arcanist/" directory (in "%s") is not a Git '. - 'working copy. You must leave "arcanist/" as a Git '. - 'working copy to use "arc upgrade".', + 'The "upgrade" workflow uses "git pull" to upgrade, but '. + 'the software directory (in "%s") is not a Git working '. + 'copy. You must leave this directory as a Git working copy to '. + 'use "arc upgrade".', $root)); } @@ -125,7 +125,7 @@ $log->writeSuccess( pht('UPGRADED'), - pht('Your copy of Arcanist is now up to date.')); + pht('This software is now up to date.')); return 0; } diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistUploadWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistUploadWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistUploadWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistUploadWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -9,7 +9,7 @@ public function getWorkflowInformation() { $help = pht(<<getSynopsis(); - if (strlen($synopsis)) { + if ($synopsis !== null) { $phutil_workflow->setSynopsis($synopsis); } @@ -154,7 +154,7 @@ } $help = $information->getHelp(); - if (strlen($help)) { + if ($help !== null) { // Unwrap linebreaks in the help text so we don't get weird formatting. $help = preg_replace("/(?<=\S)\n(?=\S)/", ' ', $help); @@ -534,7 +534,7 @@ $conduit_uri = $this->conduitURI; $message = phutil_console_format( "\n%s\n\n %s\n\n%s\n%s", - pht('YOU NEED TO __INSTALL A CERTIFICATE__ TO LOGIN TO PHABRICATOR'), + pht('YOU NEED TO __INSTALL A CERTIFICATE__ TO LOG IN'), pht('To do this, run: **%s**', 'arc install-certificate'), pht("The server '%s' rejected your request:", $conduit_uri), $ex->getMessage()); @@ -728,7 +728,7 @@ return $this->workingDirectory; } - final private function setParentWorkflow($parent_workflow) { + private function setParentWorkflow($parent_workflow) { $this->parentWorkflow = $parent_workflow; return $this; } @@ -1234,6 +1234,9 @@ $commit_message = $this->newInteractiveEditor($template) ->setName(pht('commit-message')) + ->setTaskMessage(pht( + 'Supply commit message for uncommitted changes, then save and '. + 'exit.')) ->editInteractively(); if ($commit_message === $template) { @@ -1377,7 +1380,7 @@ )); } - final private function loadBundleFromConduit( + private function loadBundleFromConduit( ConduitClient $conduit, $params) { @@ -1562,7 +1565,7 @@ * @return void */ final protected function writeStatusMessage($msg) { - fwrite(STDERR, $msg); + PhutilSystem::writeStderr($msg); } final public function writeInfo($title, $message) { @@ -1954,11 +1957,10 @@ } catch (ConduitClientException $ex) { if ($ex->getErrorCode() == 'ERR-CONDUIT-CALL') { $reasons[] = pht( - 'This version of Arcanist is more recent than the version of '. - 'Phabricator you are connecting to: the Phabricator install is '. - 'out of date and does not have support for identifying '. - 'repositories by callsign or URI. Update Phabricator to enable '. - 'these features.'); + 'This software version on the server you are connecting to is out '. + 'of date and does not have support for identifying repositories '. + 'by callsign or URI. Update the server sofwware to enable these '. + 'features.'); return array(null, $reasons); } throw $ex; @@ -2201,9 +2203,8 @@ throw new ArcanistUsageException( pht( - "Unable to find a browser command to run. Set '%s' in your ". - "Arcanist config to specify a command to use.", - 'browser')); + 'Unable to find a browser command to run. Set "browser" in your '. + 'configuration to specify a command to use.')); } diff -Nru phabricator-0~git20200925/arcanist/src/workflow/ArcanistWorkWorkflow.php phabricator-0~git20220903/arcanist/src/workflow/ArcanistWorkWorkflow.php --- phabricator-0~git20200925/arcanist/src/workflow/ArcanistWorkWorkflow.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/workflow/ArcanistWorkWorkflow.php 2022-05-17 23:15:03.000000000 +0000 @@ -28,15 +28,15 @@ a task name (like "T123"), or a new symbol. If you provide a symbol which currently does not identify any ongoing work, -Arcanist will create a new branch or bookmark with the name you provide. +a new branch or bookmark will be created with the name you provide. -If you provide the name of an existing branch or bookmark, Arcanist will switch -to that branch or bookmark. +If you provide the name of an existing branch or bookmark, the working copy +will be switched to that branch or bookmark. -If you provide the name of a revision or task, Arcanist will look for a related -branch or bookmark that exists in the working copy. If it finds one, it will -switch to it. If it does not find one, it will attempt to create a new branch -or bookmark. +If you provide the name of a revision or task, the workflow will look for a +related branch or bookmark that already exists in the working copy. If one is +found, it will switch to it. If it does not find one, it will attempt to create +a new branch or bookmark. When "arc work" creates a branch or bookmark, it will use **--start** as the branchpoint if it is provided. Otherwise, the current working copy state will diff -Nru phabricator-0~git20200925/arcanist/src/xsprintf/gitsprintf.php phabricator-0~git20220903/arcanist/src/xsprintf/gitsprintf.php --- phabricator-0~git20200925/arcanist/src/xsprintf/gitsprintf.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/xsprintf/gitsprintf.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,64 @@ + -- ... + + // These commands disambiguate ref selectors from paths using "--", but + // have no mechanism for disambiguating ref selectors from flags. + + // Thus, there appears to be no way (in the general case) to safely + // invoke these commands with an arbitrary ref selector string: ref + // selector strings like "--flag" may be interpreted as flags, not as + // ref selectors. + + // To resolve this, we reject any ref selector which begins with "-". + // These selectors are never valid anyway, so there is no loss of overall + // correctness. It would be more desirable to pass them to Git in a way + // that guarantees Git inteprets the string as a ref selector, but it + // appears that no mechanism exists to allow this. + + if (preg_match('(^-)', $value)) { + throw new Exception( + pht( + 'Git ref selector "%s" is not a valid selector and can not be '. + 'passed to the Git CLI safely in the general case.', + $value)); + } + break; + case 'R': + $type = 's'; + break; + } + + $pattern[$pos] = $type; +} diff -Nru phabricator-0~git20200925/arcanist/src/xsprintf/__tests__/PhutilGitsprintfTestCase.php phabricator-0~git20220903/arcanist/src/xsprintf/__tests__/PhutilGitsprintfTestCase.php --- phabricator-0~git20200925/arcanist/src/xsprintf/__tests__/PhutilGitsprintfTestCase.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/xsprintf/__tests__/PhutilGitsprintfTestCase.php 2022-05-17 23:15:03.000000000 +0000 @@ -0,0 +1,40 @@ + 'HEAD', + 'master' => 'master', + 'a..b' => 'a..b', + 'feature^' => 'feature^', + '--flag' => false, + ); + + foreach ($selectors as $input => $expect) { + $caught = null; + + try { + $output = gitsprintf('%s', $input); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + if ($caught !== null) { + $actual = false; + } else { + $actual = $output; + } + + $this->assertEqual( + $expect, + $actual, + pht( + 'Result for input "%s".', + $input)); + } + } + +} diff -Nru phabricator-0~git20200925/arcanist/src/xsprintf/xsprintf.php phabricator-0~git20220903/arcanist/src/xsprintf/xsprintf.php --- phabricator-0~git20200925/arcanist/src/xsprintf/xsprintf.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/src/xsprintf/xsprintf.php 2022-05-17 23:15:03.000000000 +0000 @@ -67,6 +67,18 @@ } if ($callback !== null) { + + // See T13588 and D21500. This function uses "$callback()", instead + // of "call_user_func()", to simplify reference behavior: some of + // these arguments must be passed by reference. + + // Prior to PHP7, this syntax will not work if "$callback" is a + // string referencing a static method, like "C::m". + + // This syntax does work if "$callback" is an array referencing + // a static method, like "array('C', 'm')", in all versions of PHP + // since PHP 5.4. + $callback($userdata, $pattern, $pos, $argv[$arg], $len); } } diff -Nru phabricator-0~git20200925/arcanist/support/arcanoid/arcanoid.py phabricator-0~git20220903/arcanist/support/arcanoid/arcanoid.py --- phabricator-0~git20200925/arcanist/support/arcanoid/arcanoid.py 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/support/arcanoid/arcanoid.py 2022-05-17 23:15:03.000000000 +0000 @@ -212,11 +212,16 @@ i = int(time.time() / 0.8) for x in range(width): for y in range(6): - game.addch(height / 2 + y - 3 + (x / 8 + i) % 2, x, - curses.ACS_BLOCK, - curses.A_BOLD | curses.color_pair(colors[y])) - game.addstr(height / 2, (width - len(message)) / 2, message, - curses.A_BOLD | curses.color_pair(7)) + game.addch( + int(height / 2 + y - 3 + (x / 8 + i) % 2), + x, + curses.ACS_BLOCK, + curses.A_BOLD | curses.color_pair(colors[y])) + game.addstr( + int(height / 2), + int((width - len(message)) / 2), + message, + curses.A_BOLD | curses.color_pair(7)) game.refresh() status.refresh() diff -Nru phabricator-0~git20200925/arcanist/support/hg/arc-hg.py phabricator-0~git20220903/arcanist/support/hg/arc-hg.py --- phabricator-0~git20200925/arcanist/support/hg/arc-hg.py 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/support/hg/arc-hg.py 2022-05-17 23:15:03.000000000 +0000 @@ -21,18 +21,123 @@ hg, i18n, node, - registrar, ) _ = i18n._ cmdtable = {} -command = registrar.command(cmdtable) + +# Older veresions of Mercurial (~4.7) moved the command function and the +# remoteopts object to different modules. Using try/except here to attempt +# allowing this module to load properly, despite whether individual commands +# will work properly on older versions of Mercurial or not. +# https://phab.mercurial-scm.org/rHG46ba2cdda476ac53a8a8f50e4d9435d88267db60 +# https://phab.mercurial-scm.org/rHG04baab18d60a5c833ab3190506147e01b3c6d12c +try: + from mercurial import registrar + command = registrar.command(cmdtable) +except: + command = cmdutil.command(cmdtable) + +try: + remoteopts = cmdutil.remoteopts +except: + from mercurial import commands + remoteopts = commands.remoteopts + +try: + parseurl = hg.parseurl +except: + from mercurial import utils + parseurl = utils.urlutil.parseurl + +@command( + b'arc-amend', + [ + (b'l', + b'logfile', + b'', + _(b'read commit message from file'), + _(b'FILE')), + (b'm', + b'message', + b'', + _(b'use text as commit message'), + _(b'TEXT')), + (b'u', + b'user', + b'', + _(b'record the specified user as committer'), + _(b'USER')), + (b'd', + b'date', + b'', + _(b'record the specified date as commit date'), + _(b'DATE')), + (b'A', + b'addremove', + False, + _(b'mark new/missing files as added/removed before committing')), + (b'n', + b'note', + b'', + _(b'store a note on amend'), + _(b'TEXT')), + ], + _(b'[OPTION]')) +def amend(ui, repo, source=None, **opts): + """amend + + Uses Mercurial internal API to amend changes to a non-head commit. + + (This is an Arcanist extension to Mercurial.) + + Returns 0 if amending succeeds, 1 otherwise. + """ + + # The option keys seem to come in as 'str' type but the cmdutil.amend() code + # expects them as binary. To account for both Python 2 and Python 3 + # compatibility, insert the value under both 'str' and binary type. + newopts = {} + for key in opts: + val = opts.get(key) + newopts[key] = val + if isinstance(key, str): + newkey = key.encode('UTF-8') + newopts[newkey] = val + + orig = repo[b'.'] + extra = {} + pats = [] + cmdutil.amend(ui, repo, orig, extra, pats, newopts) + + """ + # This will allow running amend on older versions of Mercurial, ~3.5, however + # the behavior on those versions will squash child commits of the working + # directory into the amended commit which is undesired. + try: + cmdutil.amend(ui, repo, orig, extra, pats, newopts) + except: + def commitfunc(ui, repo, message, match, opts): + return repo.commit( + message, + opts.get('user') or orig.user(), + opts.get('date') or orig.date(), + match, + extra=extra) + cmdutil.amend(ui, repo, commitfunc, orig, extra, pats, newopts) + """ + + return 0 @command( b'arc-ls-markers', - [(b'', b'output', b'', - _(b'file to output refs to'), _(b'FILE')), - ] + cmdutil.remoteopts, + [ + (b'', + b'output', + b'', + _(b'file to output refs to'), + _(b'FILE')), + ] + remoteopts, _(b'[--output FILENAME] [SOURCE]')) def lsmarkers(ui, repo, source=None, **opts): """list markers @@ -168,7 +273,7 @@ markers = [] - source, branches = hg.parseurl(ui.expandpath(source)) + source, branches = parseurl(ui.expandpath(source)) remote = hg.peer(repo, opts, source) with remote.commandexecutor() as e: diff -Nru phabricator-0~git20200925/arcanist/support/init/init-script.php phabricator-0~git20220903/arcanist/support/init/init-script.php --- phabricator-0~git20200925/arcanist/support/init/init-script.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/support/init/init-script.php 2022-05-17 23:15:03.000000000 +0000 @@ -50,6 +50,21 @@ // See T13296. On macOS under PHP 7.3.x, PCRE currently segfaults after // "fork()" if "pcre.jit" is enabled. 'pcre.jit' => 0, + + // See PHI1894. This option was introduced in PHP 7.4, and removes the + // "args" value from exception backtraces. We have some unit tests which + // inspect "args", and this option generally obscures useful debugging + // information without any benefit in the context of Phabricator. + 'zend.exception_ignore_args' => 0, + + // See T13100. We'd like the regex engine to fail, rather than segfault, + // if handed a pathological regular expression. + 'pcre.backtrack_limit' => 10000, + 'pcre.recusion_limit' => 10000, + + // NOTE: Phabricator applies a similar set of startup options for Web + // environments in "PhabricatorStartup". Changes here may also be + // appropriate to apply there. ); foreach ($config_map as $config_key => $config_value) { @@ -88,8 +103,11 @@ ))); // Disable the insanely dangerous XML entity loader by default. + // PHP 8 deprecates this function and disables this by default; remove once + // PHP 7 is no longer supported or a future version has removed the function + // entirely. if (function_exists('libxml_disable_entity_loader')) { - libxml_disable_entity_loader(true); + @libxml_disable_entity_loader(true); } $root = dirname(dirname(dirname(__FILE__))); @@ -97,8 +115,6 @@ PhutilErrorHandler::initialize(); - PhutilErrorHandler::initialize(); - // If "variables_order" excludes "E", silently repair it so that $_ENV has // the values we expect. PhutilExecutionEnvironment::repairMissingVariablesOrder(); diff -Nru phabricator-0~git20200925/arcanist/support/lib/extract-symbols.php phabricator-0~git20220903/arcanist/support/lib/extract-symbols.php --- phabricator-0~git20200925/arcanist/support/lib/extract-symbols.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/support/lib/extract-symbols.php 2022-05-17 23:15:03.000000000 +0000 @@ -23,8 +23,8 @@ Symbols are reported in JSON on stdout. - This script is used internally by libphutil/arcanist to build maps of - library symbols. + This script is used internally by Arcanist to build maps of library + symbols. It would be nice to eventually implement this as a C++ xhpast binary, as it's relatively stable and performance is currently awful @@ -38,7 +38,11 @@ array( 'name' => 'all', 'help' => pht( - 'Report all symbols, including built-ins and declared externals.'), + 'Emit all symbols, including built-ins and declared externals.'), + ), + array( + 'name' => 'builtins', + 'help' => pht('Emit builtin symbols.'), ), array( 'name' => 'ugly', @@ -52,14 +56,32 @@ )); $paths = $args->getArg('path'); -if (count($paths) !== 1) { - throw new Exception(pht('Specify exactly one path!')); -} -$path = Filesystem::resolvePath(head($paths)); $show_all = $args->getArg('all'); +$show_builtins = $args->getArg('builtins'); + +if ($show_all && $show_builtins) { + throw new PhutilArgumentUsageException( + pht( + 'Flags "--all" and "--builtins" are not compatible.')); +} -$source_code = Filesystem::readFile($path); +if ($show_builtins && $paths) { + throw new PhutilArgumentUsageException( + pht( + 'Flag "--builtins" may not be used with a path.')); +} + +if ($show_builtins) { + $path = ''; + $source_code = ''; +} else { + if (count($paths) !== 1) { + throw new Exception(pht('Specify exactly one path!')); + } + $path = Filesystem::resolvePath(head($paths)); + $source_code = Filesystem::readFile($path); +} try { $tree = XHPASTTree::newFromData($source_code); @@ -197,7 +219,13 @@ $symbol = array_shift($params); $type = 'function'; $symbol_value = $symbol->getStringLiteralValue(); - $pos = strpos($symbol_value, '::'); + + if ($symbol_value !== null) { + $pos = strpos($symbol_value, '::'); + } else { + $pos = false; + } + if ($pos) { $type = 'class'; $symbol_value = substr($symbol_value, 0, $pos); @@ -474,6 +502,14 @@ $required_symbols[$type][$name] = $spec['symbol']->getOffset(); } +if ($show_builtins) { + foreach ($builtins as $type => $builtin_symbols) { + foreach ($builtin_symbols as $builtin_symbol => $ignored) { + $declared_symbols[$type][$builtin_symbol] = null; + } + } +} + $result = array( 'have' => $declared_symbols, 'need' => $required_symbols, @@ -543,8 +579,6 @@ 'parent' => true, 'self' => true, - 'PhutilBootloader' => true, - // PHP7 defines these new parent classes of "Exception", but they do not // exist prior to PHP7. It's possible to use them safely in PHP5, in // some cases, to write code which is compatible with either PHP5 or @@ -570,12 +604,6 @@ 'isset' => true, 'die' => true, - // These are provided by libphutil but not visible in the map. - - 'phutil_is_windows' => true, - 'phutil_load_library' => true, - 'phutil_is_hiphop_runtime' => true, - // HPHP/i defines these functions as 'internal', but they are NOT // builtins and do not exist in vanilla PHP. Make sure we don't mark // them as builtin since we need to add dependencies for them. diff -Nru phabricator-0~git20200925/arcanist/support/lib/rebuild-map.php phabricator-0~git20220903/arcanist/support/lib/rebuild-map.php --- phabricator-0~git20200925/arcanist/support/lib/rebuild-map.php 2020-09-25 09:09:39.000000000 +0000 +++ phabricator-0~git20220903/arcanist/support/lib/rebuild-map.php 2022-05-17 23:15:03.000000000 +0000 @@ -17,10 +17,6 @@ $args->parse( array( array( - 'name' => 'quiet', - 'help' => pht('Do not write status messages to stderr.'), - ), - array( 'name' => 'drop-cache', 'help' => pht( 'Drop the symbol cache and rebuild the entire map from scratch.'), @@ -56,7 +52,6 @@ $root = Filesystem::resolvePath(head($root)); $builder = new PhutilLibraryMapBuilder($root); -$builder->setQuiet($args->getArg('quiet')); $builder->setSubprocessLimit($args->getArg('limit')); if ($args->getArg('drop-cache')) { diff -Nru phabricator-0~git20200925/debian/arc.1 phabricator-0~git20220903/debian/arc.1 --- phabricator-0~git20200925/debian/arc.1 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/arc.1 1970-01-01 00:00:00.000000000 +0000 @@ -1,2244 +0,0 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` "" -. ds C' "" -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -. ds C` -. ds C' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.\" -.\" Avoid warning from groff about undefined register 'F'. -.de IX -.. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} -. \} -.\} -.rr rF -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "ARC 1" -.TH ARC 1 "2016-10-24" "" "User Commands" -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -arc \- arcanist, a code review and revision management utility -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBarc\fR \fIcommand\fR [\fIoptions\fR] [\fIargs\fR] -This help file provides a detailed command reference. -.SH "COMMAND REFERENCE" -.IX Header "COMMAND REFERENCE" -\&\fBalias\fR -.PP -\&\fBalias\fR \fIcommand\fR -.PP -\&\fBalias\fR \fIcommand\fR \fItarget\fR \*(-- [\fIoptions\fR] -.Sp -.RS 4 -Supports: cli -Create an alias from \fIcommand\fR to \fItarget\fR (optionally, with -\&\fIoptions\fR). For example: -.Sp -.Vb 1 -\& arc alias fpatch patch \-\- \-\-force -.Ve -.Sp -\&...will create a new 'arc' command, 'arc fpatch', which invokes -\&'arc patch \-\-force ...' when run. \s-1NOTE:\s0 use \*(L"\-\-\*(R" before specifying -options! -.Sp -If you start an alias with \*(L"!\*(R", the remainder of the alias will be -invoked as a shell command. For example, if you want to implement -\&'arc ls', you can do so like this: -.Sp -.Vb 1 -\& arc alias ls \*(Aq!ls\*(Aq -.Ve -.Sp -You can now run \*(L"arc ls\*(R" and it will behave like \*(L"ls\*(R". Of course, this -example is silly and would make your life worse. -.Sp -You can not overwrite builtins, including 'alias' itself. The builtin -will always execute, even if it was added after your alias. -.Sp -To remove an alias, run: -.Sp -.Vb 1 -\& arc alias fpatch -.Ve -.Sp -Without any arguments, 'arc alias' will list aliases. -.RE -.PP -\&\fBamend\fR [\-\-revision \fIrevision_id\fR] [\-\-show] -.Sp -.RS 4 -Supports: git, hg -Amend the working copy, synchronizing the local commit message from -Differential. -.Sp -Supported in Mercurial 2.2 and newer. -.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 -.IX Item "--revision revision_id" -.RE -.RS 4 -.Sp -.RS 4 -Use the message from a specific revision. If you do not specify -a revision, arc will guess which revision is in the working -copy. -.RE -.RE -.RS 4 -.IP "\fI\-\-show\fR" 4 -.IX Item "--show" -.RE -.RS 4 -.Sp -.RS 4 -Show the amended commit message, without modifying the working -copy. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBanoid\fR -.Sp -.RS 4 -There's only one way to find out... -.RE -.PP -\&\fBbackout\fR -.Sp -.RS 4 -Reverts/backouts on a previous commit. Supports: git, hg -.Sp -.RS 4 -Command is used like this: arc backout | -Entering a differential revision will only work if there is only one commit -associated with the revision. This requires your working copy is up to date -and that the commit exists in the working copy. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBbookmark\fR [\fIoptions\fR] -.PP -\&\fBbookmark\fR \fIname\fR [\fIstart\fR] -.Sp -.RS 4 -Supports: hg -Alias for arc feature. -.IP "\fI\-\-by\-status\fR" 4 -.IX Item "--by-status" -.RE -.RS 4 -.Sp -.RS 4 -Sort branches by status instead of time. -.RE -.RE -.RS 4 -.IP "\fI\-\-output\fR \fIformat\fR" 4 -.IX Item "--output format" -.RE -.RS 4 -.Sp -.RS 4 -With 'json', show features in machine-readable \s-1JSON\s0 format. -.RE -.RE -.RS 4 -.IP "\fI\-\-view\-all\fR" 4 -.IX Item "--view-all" -.RE -.RS 4 -.Sp -.RS 4 -Include closed and abandoned revisions. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBbranch\fR [\fIoptions\fR] -.PP -\&\fBbranch\fR \fIname\fR [\fIstart\fR] -.Sp -.RS 4 -Supports: git -Alias for arc feature. -.IP "\fI\-\-by\-status\fR" 4 -.IX Item "--by-status" -.RE -.RS 4 -.Sp -.RS 4 -Sort branches by status instead of time. -.RE -.RE -.RS 4 -.IP "\fI\-\-output\fR \fIformat\fR" 4 -.IX Item "--output format" -.RE -.RS 4 -.Sp -.RS 4 -With 'json', show features in machine-readable \s-1JSON\s0 format. -.RE -.RE -.RS 4 -.IP "\fI\-\-view\-all\fR" 4 -.IX Item "--view-all" -.RE -.RS 4 -.Sp -.RS 4 -Include closed and abandoned revisions. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBbrowse\fR [\fIoptions\fR] \fIpath\fR ... -.PP -\&\fBbrowse\fR [\fIoptions\fR] \fIobject\fR ... -.Sp -.RS 4 -Supports: git, hg, svn -Open a file or object (like a task or revision) in your web browser. -.Sp -.Vb 3 -\& $ arc browse README # Open a file in Diffusion. -\& $ arc browse T123 # View a task. -\& $ arc browse HEAD # View a symbolic commit. -.Ve -.Sp -Set the 'browser' value using 'arc set\-config' to select a browser. If -no browser is set, the command will try to guess which browser to use. -.IP "\fI\-\-branch\fR \fIbranch_name\fR" 4 -.IX Item "--branch branch_name" -.RE -.RS 4 -.Sp -.RS 4 -Default branch name to view on server. Defaults to \*(L"master\*(R". -.RE -.RE -.RS 4 -.IP "\fI\-\-force\fR" 4 -.IX Item "--force" -.RE -.RS 4 -.Sp -.RS 4 -Open arguments as paths, even if they do not exist in the -working copy. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBcall-conduit\fR \fImethod\fR -.Sp -.RS 4 -Supports: http, https -Allows you to make a raw Conduit method call: -.Sp -.Vb 3 -\& \- Run this command from a working directory. -\& \- Call parameters are REQUIRED and read as a JSON blob from stdin. -\& \- Results are written to stdout as a JSON blob. -.Ve -.Sp -This workflow is primarily useful for writing scripts which integrate -with Phabricator. Examples: -.Sp -.Vb 2 -\& $ echo \*(Aq{}\*(Aq | arc call\-conduit conduit.ping -\& $ echo \*(Aq{"phid":"PHID\-FILE\-xxxx"}\*(Aq | arc call\-conduit file.download -.Ve -.RE -.PP -\&\fBclose\fR \fItask_id\fR [\fIoptions\fR] - Close a task or otherwise update its status. -.IP "\fI\-\-list\-statuses\fR" 4 -.IX Item "--list-statuses" -.Sp -.RS 4 -Show available status options and exit. -.RE -.IP "\fI\-\-message\fR \fIcomment\fR, \fI\-m\fR \fIcomment\fR" 4 -.IX Item "--message comment, -m comment" -.Sp -.RS 4 -Provide a comment with your status change. -.RE -.IP "\fI\-\-status\fR \fIstatus\fR, \fI\-s\fR \fIstatus\fR" 4 -.IX Item "--status status, -s status" -.Sp -.RS 4 -Specify a new status. Valid status options can be seen with the -`list\-statuses` argument. -.RE -.PP -\&\fBclose-revision\fR [\fIoptions\fR] \fIrevision\fR -.Sp -.RS 4 -Supports: git, hg, svn -Close a revision which has been committed (svn) or pushed (git, hg). -You should not normally need to do this: arc commit (svn), arc amend -(git, hg), arc land (git, hg), or repository tracking on the master -remote repository should do it for you. However, if these mechanisms -have failed for some reason you can use this command to manually -change a revision status from \*(L"Accepted\*(R" to \*(L"Closed\*(R". -.IP "\fI\-\-finalize\fR" 4 -.IX Item "--finalize" -.RE -.RS 4 -.Sp -.RS 4 -Close only if the repository is untracked and the revision is -accepted. Continue even if the close can't happen. This is a -soft version of '' used by other workflows. -.RE -.RE -.RS 4 -.IP "\fI\-\-quiet\fR" 4 -.IX Item "--quiet" -.RE -.RS 4 -.Sp -.RS 4 -Do not print a success message. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBcommit\fR [\-\-revision \fIrevision_id\fR] [\-\-show] -.Sp -.RS 4 -Supports: svn -Commit a revision which has been accepted by a reviewer. -.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 -.IX Item "--revision revision_id" -.RE -.RS 4 -.Sp -.RS 4 -Commit a specific revision. If you do not specify a revision, -arc will look for committable revisions. -.RE -.RE -.RS 4 -.IP "\fI\-\-show\fR" 4 -.IX Item "--show" -.RE -.RS 4 -.Sp -.RS 4 -Show the command which would be issued, but do not actually -commit anything. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBcover\fR [\-\-rev \fIrevision\fR] [\fIpath\fR ...] -.Sp -.RS 4 -Supports: svn, git, hg -Cover your... professional reputation. Show blame for the lines you -changed in your working copy (svn) or since some commit (hg, git). -This will take a minute because blame takes a minute, especially under -\&\s-1SVN.\s0 -.IP "\fI\-\-rev\fR \fIrevision\fR" 4 -.IX Item "--rev revision" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Cover changes since a specific revision. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBdiff\fR [\fIpaths\fR] (svn) -.PP -\&\fBdiff\fR [\fIcommit\fR] (git, hg) -.Sp -.RS 4 -Supports: git, svn, hg -Generate a Differential diff or revision from local changes. -.Sp -Under git and mercurial, you can specify a commit (like \fIHEAD^^^\fR -or \fImaster\fR) and Differential will generate a diff against the -merge base of that commit and your current working directory parent. -.Sp -Under svn, you can choose to include only some of the modified files -in the working copy in the diff by specifying their paths. If you -omit paths, all changes are included in the diff. -.IP "\fI\-\-add\-all\fR, \fI\-a\fR" 4 -.IX Item "--add-all, -a" -.RE -.RS 4 -.Sp -.RS 4 -Automatically add all unstaged and uncommitted files to the -commit. -.RE -.RE -.RS 4 -.IP "\fI\-\-advice\fR" 4 -.IX Item "--advice" -.RE -.RS 4 -.Sp -.RS 4 -Require excuse for lint advice in addition to lint warnings and -errors. -.RE -.RE -.RS 4 -.IP "\fI\-\-allow\-untracked\fR" 4 -.IX Item "--allow-untracked" -.RE -.RS 4 -.Sp -.RS 4 -Skip checks for untracked files in the working copy. -.RE -.RE -.RS 4 -.IP "\fI\-\-amend\-all\fR" 4 -.IX Item "--amend-all" -.RE -.RS 4 -.Sp -.RS 4 -When linting git repositories, amend \s-1HEAD\s0 with all patches -suggested by lint without prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-amend\-autofixes\fR" 4 -.IX Item "--amend-autofixes" -.RE -.RS 4 -.Sp -.RS 4 -When linting git repositories, amend \s-1HEAD\s0 with autofix patches -suggested by lint without prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-apply\-patches\fR" 4 -.IX Item "--apply-patches" -.RE -.RS 4 -.Sp -.RS 4 -Apply patches suggested by lint to the working copy without -prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-base\fR \fIrules\fR" 4 -.IX Item "--base rules" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Additional rules for determining base revision. -.RE -.RE -.RS 4 -.IP "\fI\-\-browse\fR" 4 -.IX Item "--browse" -.RE -.RS 4 -.Sp -.RS 4 -After creating a diff or revision, open it in a web browser. -.RE -.RE -.RS 4 -.IP "\fI\-\-cache\fR \fIbool\fR" 4 -.IX Item "--cache bool" -.RE -.RS 4 -.Sp -.Vb 1 -\& 0 to disable lint cache, 1 to enable (default). -.Ve -.IP "\fI\-\-cc\fR \fIusernames\fR" 4 -.IX Item "--cc usernames" -.RE -.RS 4 -.Sp -.RS 4 -When creating a revision, add CCs. -.RE -.RE -.RS 4 -.IP "\fI\-\-coverage\fR" 4 -.IX Item "--coverage" -.RE -.RS 4 -.Sp -.RS 4 -Always enable coverage information. -.RE -.RE -.RS 4 -.IP "\fI\-\-create\fR" 4 -.IX Item "--create" -.RE -.RS 4 -.Sp -.RS 4 -Always create a new revision. -.RE -.RE -.RS 4 -.IP "\fI\-\-edit\fR" 4 -.IX Item "--edit" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -When updating a revision under git, edit revision information -before updating. -.RE -.RE -.RS 4 -.IP "\fI\-\-encoding\fR \fIencoding\fR" 4 -.IX Item "--encoding encoding" -.RE -.RS 4 -.Sp -.RS 4 -Attempt to convert non \s-1UTF\-8\s0 hunks into specified encoding. -.RE -.RE -.RS 4 -.IP "\fI\-\-excuse\fR \fIexcuse\fR" 4 -.IX Item "--excuse excuse" -.RE -.RS 4 -.Sp -.RS 4 -Provide a prepared in advance excuse for any lints/tests shall -they fail. -.RE -.RE -.RS 4 -.IP "\fI\-\-head\fR \fIcommit\fR" 4 -.IX Item "--head commit" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git -Specify the end of the commit range. This disables many -Arcanist/Phabricator features which depend on having access to -the working copy. -.RE -.RE -.RS 4 -.IP "\fI\-\-ignore\-unsound\-tests\fR" 4 -.IX Item "--ignore-unsound-tests" -.RE -.RS 4 -.Sp -.RS 4 -Ignore unsound test failures without prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-json\fR" 4 -.IX Item "--json" -.RE -.RS 4 -.Sp -.RS 4 -Emit machine-readable \s-1JSON. EXPERIMENTAL\s0! Probably does not -work! -.RE -.RE -.RS 4 -.IP "\fI\-\-less\-context\fR" 4 -.IX Item "--less-context" -.RE -.RS 4 -.Sp -.RS 4 -Normally, files are diffed with full context: the entire file -is sent to Differential so reviewers can 'show more' and see -it. If you are making changes to very large files with tens of -thousands of lines, this may not work well. With this flag, a -diff will be created that has only a few lines of context. -.RE -.RE -.RS 4 -.IP "\fI\-\-lintall\fR" 4 -.IX Item "--lintall" -.RE -.RS 4 -.Sp -.RS 4 -Raise all lint warnings, not just those on lines you changed. -.RE -.RE -.RS 4 -.IP "\fI\-\-message\fR \fImessage\fR, \fI\-m\fR \fImessage\fR" 4 -.IX Item "--message message, -m message" -.RE -.RS 4 -.Sp -.RS 4 -When updating a revision, use the specified message instead of -prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-message\-file\fR \fIfile\fR, \fI\-F\fR \fIfile\fR" 4 -.IX Item "--message-file file, -F file" -.RE -.RS 4 -.Sp -.RS 4 -When creating a revision, read revision information from this -file. -.RE -.RE -.RS 4 -.IP "\fI\-\-never\-apply\-patches\fR" 4 -.IX Item "--never-apply-patches" -.RE -.RS 4 -.Sp -.RS 4 -Never apply patches suggested by lint. -.RE -.RE -.RS 4 -.IP "\fI\-\-no\-amend\fR" 4 -.IX Item "--no-amend" -.RE -.RS 4 -.Sp -.RS 4 -Never amend commits in the working copy with lint patches. -.RE -.RE -.RS 4 -.IP "\fI\-\-no\-coverage\fR" 4 -.IX Item "--no-coverage" -.RE -.RS 4 -.Sp -.RS 4 -Always disable coverage information. -.RE -.RE -.RS 4 -.IP "\fI\-\-no\-diff\fR" 4 -.IX Item "--no-diff" -.RE -.RS 4 -.Sp -.RS 4 -Only run lint and unit tests. Intended for internal use. -.RE -.RE -.RS 4 -.IP "\fI\-\-nolint\fR" 4 -.IX Item "--nolint" -.RE -.RS 4 -.Sp -.RS 4 -Do not run lint. -.RE -.RE -.RS 4 -.IP "\fI\-\-nounit\fR" 4 -.IX Item "--nounit" -.RE -.RS 4 -.Sp -.RS 4 -Do not run unit tests. -.RE -.RE -.RS 4 -.IP "\fI\-\-only\fR" 4 -.IX Item "--only" -.RE -.RS 4 -.Sp -.RS 4 -Only generate a diff, without running lint, unit tests, or -other auxiliary steps. See also \-\-preview. -.RE -.RE -.RS 4 -.IP "\fI\-\-only\-new\fR \fIbool\fR" 4 -.IX Item "--only-new bool" -.RE -.RS 4 -.Sp -.RS 4 -Display only lint messages not present in the original code. -.RE -.RE -.RS 4 -.IP "\fI\-\-plan\-changes\fR" 4 -.IX Item "--plan-changes" -.RE -.RS 4 -.Sp -.RS 4 -Create or update a revision without requesting a code review. -.RE -.RE -.RS 4 -.IP "\fI\-\-preview\fR" 4 -.IX Item "--preview" -.RE -.RS 4 -.Sp -.RS 4 -Instead of creating or updating a revision, only create a diff, -which you may later attach to a revision. This still runs lint -unit tests. See also \-\-only. -.RE -.RE -.RS 4 -.IP "\fI\-\-raw\fR" 4 -.IX Item "--raw" -.RE -.RS 4 -.Sp -.RS 4 -Read diff from stdin, not from the working copy. This disables -many Arcanist/Phabricator features which depend on having -access to the working copy. -.RE -.RE -.RS 4 -.IP "\fI\-\-raw\-command\fR \fIcommand\fR" 4 -.IX Item "--raw-command command" -.RE -.RS 4 -.Sp -.RS 4 -Generate diff by executing a specified command, not from the -working copy. This disables many Arcanist/Phabricator features -which depend on having access to the working copy. -.RE -.RE -.RS 4 -.IP "\fI\-\-reviewers\fR \fIusernames\fR" 4 -.IX Item "--reviewers usernames" -.RE -.RS 4 -.Sp -.RS 4 -When creating a revision, add reviewers. -.RE -.RE -.RS 4 -.IP "\fI\-\-skip\-binaries\fR" 4 -.IX Item "--skip-binaries" -.RE -.RS 4 -.Sp -.RS 4 -Do not upload binaries (like images). -.RE -.RE -.RS 4 -.IP "\fI\-\-skip\-staging\fR" 4 -.IX Item "--skip-staging" -.RE -.RS 4 -.Sp -.RS 4 -Do not copy changes to the staging area. -.RE -.RE -.RS 4 -.IP "\fI\-\-uncommitted\fR" 4 -.IX Item "--uncommitted" -.RE -.RS 4 -.Sp -.RS 4 -Supports: hg -Suppress warning about uncommitted changes. -.RE -.RE -.RS 4 -.IP "\fI\-\-update\fR \fIrevision_id\fR" 4 -.IX Item "--update revision_id" -.RE -.RS 4 -.Sp -.RS 4 -Always update a specific revision. -.RE -.RE -.RS 4 -.IP "\fI\-\-use\-commit\-message\fR \fIcommit\fR, \fI\-C\fR \fIcommit\fR" 4 -.IX Item "--use-commit-message commit, -C commit" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git -Read revision information from a specific commit. -.RE -.RE -.RS 4 -.IP "\fI\-\-verbatim\fR" 4 -.IX Item "--verbatim" -.RE -.RS 4 -.Sp -.RS 4 -Supports: hg, git -When creating a revision, try to use the working copy commit -message verbatim, without prompting to edit it. When updating a -revision, update some fields from the local commit message. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBdownload\fR \fIfile\fR [\-\-as \fIname\fR] [\-\-show] -.Sp -.RS 4 -Supports: filesystems -Download a file to local disk, e.g.: -.Sp -.Vb 1 -\& $ arc download F33 # Download file \*(AqF33\*(Aq -.Ve -.IP "\fI\-\-as\fR \fIname\fR" 4 -.IX Item "--as name" -.RE -.RS 4 -.Sp -.RS 4 -Save the file with a specific name rather than the default. -.RE -.RE -.RS 4 -.IP "\fI\-\-show\fR" 4 -.IX Item "--show" -.RE -.RS 4 -.Sp -.RS 4 -Write file to stdout instead of to disk. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBexport\fR [\fIpaths\fR] \fIformat\fR (svn) -.PP -\&\fBexport\fR [\fIcommit_range\fR] \fIformat\fR (git, hg) -.PP -\&\fBexport\fR \fI\-\-revision\fR \fIrevision_id\fR \fIformat\fR -.PP -\&\fBexport\fR \fI\-\-diff\fR \fIdiff_id\fR \fIformat\fR -.Sp -.RS 4 -Supports: svn, git, hg -Export the local changeset (or a Differential changeset) to a file, -in some \fIformat\fR: git diff (\fI\-\-git\fR), unified diff -(\fI\-\-unified\fR), or arc bundle (\fI\-\-arcbundle\fR \fIpath\fR) format. -.IP "\fI\-\-arcbundle\fR \fIfile\fR" 4 -.IX Item "--arcbundle file" -.RE -.RS 4 -.Sp -.RS 4 -Export change as an arc bundle. This format can represent all -changes. These bundles can be applied with 'arc patch'. -.RE -.RE -.RS 4 -.IP "\fI\-\-diff\fR \fIdiff_id\fR" 4 -.IX Item "--diff diff_id" -.RE -.RS 4 -.Sp -.RS 4 -Instead of exporting changes from the working copy, export them -from a Differential diff. -.RE -.RE -.RS 4 -.IP "\fI\-\-encoding\fR \fIencoding\fR" 4 -.IX Item "--encoding encoding" -.RE -.RS 4 -.Sp -.RS 4 -Attempt to convert non \s-1UTF\-8\s0 patch into specified encoding. -.RE -.RE -.RS 4 -.IP "\fI\-\-git\fR" 4 -.IX Item "--git" -.RE -.RS 4 -.Sp -.RS 4 -Export change as a git patch. This format is more complete than -unified, but less complete than arc bundles. These patches can -be applied with 'git apply' or 'arc patch'. -.RE -.RE -.RS 4 -.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 -.IX Item "--revision revision_id" -.RE -.RS 4 -.Sp -.RS 4 -Instead of exporting changes from the working copy, export them -from a Differential revision. -.RE -.RE -.RS 4 -.IP "\fI\-\-unified\fR" 4 -.IX Item "--unified" -.RE -.RS 4 -.Sp -.RS 4 -Export change as a unified patch. This format is less complete -than git patches or arc bundles. These patches can be applied -with 'patch' or 'arc patch'. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBfeature\fR [\fIoptions\fR] -.PP -\&\fBfeature\fR \fIname\fR [\fIstart\fR] -.Sp -.RS 4 -Supports: git, hg -A wrapper on 'git branch' or 'hg bookmark'. -.Sp -Without \fIname\fR, it lists the available branches and their revision -status. -.Sp -With \fIname\fR, it creates or checks out a branch. If the branch -\&\fIname\fR doesn't exist and is in format D123 then the branch of -revision D123 is checked out. Use \fIstart\fR to specify where the new -branch will start. Use 'arc.feature.start.default' to set the default -feature start location. -.IP "\fI\-\-by\-status\fR" 4 -.IX Item "--by-status" -.RE -.RS 4 -.Sp -.RS 4 -Sort branches by status instead of time. -.RE -.RE -.RS 4 -.IP "\fI\-\-output\fR \fIformat\fR" 4 -.IX Item "--output format" -.RE -.RS 4 -.Sp -.RS 4 -With 'json', show features in machine-readable \s-1JSON\s0 format. -.RE -.RE -.RS 4 -.IP "\fI\-\-view\-all\fR" 4 -.IX Item "--view-all" -.RE -.RS 4 -.Sp -.RS 4 -Include closed and abandoned revisions. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBflag\fR [\fIobject\fR ...] -.PP -\&\fBflag\fR \fIobject\fR \-\-clear -.PP -\&\fBflag\fR \fIobject\fR [\-\-edit] [\-\-color \fIcolor\fR] [\-\-note \fInote\fR] -.Sp -.RS 4 -In the first form, list objects you've flagged. You can provide the -names of one or more objects (Maniphest tasks T#, Differential -revisions D#, Diffusion references rXXX???, or PHIDs \s-1PHID\-XXX\-\s0???) -to print only flags for those objects. -.Sp -In the second form, clear an existing flag on one object. -.Sp -In the third form, create or update a flag on one object. Color -defaults to blue and note to empty, but if you omit both you must -pass \-\-edit. -.IP "\fI\-\-clear\fR" 4 -.IX Item "--clear" -.RE -.RS 4 -.Sp -.RS 4 -Delete the flag on an object. -.RE -.RE -.RS 4 -.IP "\fI\-\-color\fR \fIcolor\fR" 4 -.IX Item "--color color" -.RE -.RS 4 -.Sp -.RS 4 -Set the color of a flag. -.RE -.RE -.RS 4 -.IP "\fI\-\-edit\fR" 4 -.IX Item "--edit" -.RE -.RS 4 -.Sp -.RS 4 -Edit the flag on an object. -.RE -.RE -.RS 4 -.IP "\fI\-\-note\fR \fInote\fR" 4 -.IX Item "--note note" -.RE -.RS 4 -.Sp -.RS 4 -Set the note on a flag. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBget-config\fR [\fIoptions\fR] \*(-- [\fIname\fR ...] -.Sp -.RS 4 -Supports: cli -Reads an arc configuration option. With no argument, reads all -options. -.Sp -With \fI\-\-verbose\fR, shows detailed information about one or more -options. -.IP "\fI\-\-verbose\fR" 4 -.IX Item "--verbose" -.RE -.RS 4 -.Sp -.RS 4 -Show detailed information about options. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBhelp\fR [\fIcommand\fR] -.PP -\&\fBhelp\fR \-\-full -.Sp -.RS 4 -Supports: english -Shows this help. With \fIcommand\fR, shows help about a specific -command. -.IP "\fI\-\-full\fR" 4 -.IX Item "--full" -.RE -.RS 4 -.Sp -.RS 4 -Print detailed information about each command. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBinstall-certificate\fR [uri] -.Sp -.RS 4 -Supports: http, https -Installs Conduit credentials into your ~/.arcrc for the given install -of Phabricator. You need to do this before you can use 'arc', as it -enables 'arc' to link your command-line activity with your account on -the web. Run this command from within a project directory to install -that project's certificate, or specify an explicit \s-1URI \s0(like -\&\*(L"https://phabricator.example.com/\*(R"). -.RE -.PP -\&\fBland\fR [\fIoptions\fR] [\fIref\fR] -.Sp -.RS 4 -Supports: git, hg -.Sp -Publish an accepted revision after review. This command is the last -step in the standard Differential pre-publish code review workflow. -.Sp -This command merges and pushes changes associated with an accepted -revision that are currently sitting in \fIref\fR, which is usually the -name of a local branch. Without \fIref\fR, the current working copy -state will be used. -.Sp -Under Git: branches, tags, and arbitrary commits (detached HEADs) -may be landed. -.Sp -Under Mercurial: branches and bookmarks may be landed, but only -onto a target of the same type. See T3855. -.Sp -The workflow selects a target branch to land onto and a remote where -the change will be pushed to. -.Sp -A target branch is selected by examining these sources in order: -.Sp -.Vb 6 -\& \- the B<\-\-onto> flag; -\& \- the upstream of the current branch, recursively (Git only); -\& \- the I configuration setting; -\& \- or by falling back to a standard default: -\& \- "master" in Git; -\& \- "default" in Mercurial. -.Ve -.Sp -A remote is selected by examining these sources in order: -.Sp -.Vb 5 -\& \- the B<\-\-remote> flag; -\& \- the upstream of the current branch, recursively (Git only); -\& \- or by falling back to a standard default: -\& \- "origin" in Git; -\& \- the default remote in Mercurial. -.Ve -.Sp -After selecting a target branch and a remote, the commits which will -be landed are printed. -.Sp -With \fB\-\-preview\fR, execution stops here, before the change is -merged. -.Sp -The change is merged with the changes in the target branch, -following these rules: -.Sp -In repositories with mutable history or with \fB\-\-squash\fR, this will -perform a squash merge (the entire branch will be represented as one -commit after the merge). -.Sp -In repositories with immutable history or with \fB\-\-merge\fR, this will -perform a strict merge (a merge commit will always be created, and -local commits will be preserved). -.Sp -The resulting commit will be given an up-to-date commit message -describing the final state of the revision in Differential. -.Sp -In Git, the merge occurs in a detached \s-1HEAD.\s0 The local branch -reference (if one exists) is not updated yet. -.Sp -With \fB\-\-hold\fR, execution stops here, before the change is pushed. -.Sp -The change is pushed into the remote. -.Sp -Consulting mystical sources of power, the workflow makes a guess -about what state you wanted to end up in after the process finishes -and the working copy is put into that state. -.Sp -The branch which was landed is deleted, unless the \fB\-\-keep\-branch\fR -flag was passed or the landing branch is the same as the target -branch. -.IP "\fI\-\-delete\-remote\fR" 4 -.IX Item "--delete-remote" -.RE -.RS 4 -.Sp -.RS 4 -Delete the feature branch in the remote after landing it. -.RE -.RE -.RS 4 -.IP "\fI\-\-hold\fR" 4 -.IX Item "--hold" -.RE -.RS 4 -.Sp -.RS 4 -Prepare the change to be pushed, but do not actually push it. -.RE -.RE -.RS 4 -.IP "\fI\-\-keep\-branch\fR" 4 -.IX Item "--keep-branch" -.RE -.RS 4 -.Sp -.RS 4 -Keep the feature branch after pushing changes to the remote (by -default, it is deleted). -.RE -.RE -.RS 4 -.IP "\fI\-\-merge\fR" 4 -.IX Item "--merge" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git -Perform a \-\-no\-ff merge, not a \-\-squash merge. If the project -is marked as having an immutable history, this is the default -behavior. -.RE -.RE -.RS 4 -.IP "\fI\-\-onto\fR \fImaster\fR" 4 -.IX Item "--onto master" -.RE -.RS 4 -.Sp -.RS 4 -Land feature branch onto a branch other than the default -('master' in git, 'default' in hg). You can change the default -by setting 'arc.land.onto.default' with `arc set\-config` or for -the entire project in .arcconfig. -.RE -.RE -.RS 4 -.IP "\fI\-\-preview\fR" 4 -.IX Item "--preview" -.RE -.RS 4 -.Sp -.RS 4 -Prints the commits that would be landed. Does not actually -modify or land the commits. -.RE -.RE -.RS 4 -.IP "\fI\-\-remote\fR \fIorigin\fR" 4 -.IX Item "--remote origin" -.RE -.RS 4 -.Sp -.RS 4 -Push to a remote other than the default ('origin' in git). -.RE -.RE -.RS 4 -.IP "\fI\-\-revision\fR \fIid\fR" 4 -.IX Item "--revision id" -.RE -.RS 4 -.Sp -.RS 4 -Use the message from a specific revision, rather than inferring -the revision based on branch content. -.RE -.RE -.RS 4 -.IP "\fI\-\-squash\fR" 4 -.IX Item "--squash" -.RE -.RS 4 -.Sp -.RS 4 -Perform a \-\-squash merge, not a \-\-no\-ff merge. If the project -is marked as having a mutable history, this is the default -behavior. -.RE -.RE -.RS 4 -.IP "\fI\-\-update\-with\-merge\fR" 4 -.IX Item "--update-with-merge" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git -When updating the feature branch, use merge instead of rebase. -This is the default behavior. Setting arc.land.update.default -to 'merge' can also be used to make this the default. -.RE -.RE -.RS 4 -.IP "\fI\-\-update\-with\-rebase\fR" 4 -.IX Item "--update-with-rebase" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git -When updating the feature branch, use rebase instead of merge. -This might make things work better in some cases. Set -arc.land.update.default to 'rebase' to make this the default. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBliberate\fR [\fIpath\fR] -.Sp -.RS 4 -Supports: libphutil -Create or update a libphutil library, generating required metadata -files like \fIinit\fR.php. -.IP "\fI\-\-all\fR" 4 -.IX Item "--all" -.RE -.RS 4 -.Sp -.RS 4 -Drop the module cache before liberating. This will completely -reanalyze the entire library. Thorough, but slow! -.RE -.RE -.RS 4 -.IP "\fI\-\-force\-update\fR" 4 -.IX Item "--force-update" -.RE -.RS 4 -.Sp -.RS 4 -Force the library map to be updated, even in the presence of -lint errors. -.RE -.RE -.RS 4 -.IP "\fI\-\-library\-name\fR \fIname\fR" 4 -.IX Item "--library-name name" -.RE -.RS 4 -.Sp -.RS 4 -Use a flag for library name rather than awaiting user input. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBlint\fR [\fIoptions\fR] [\fIpaths\fR] -.PP -\&\fBlint\fR [\fIoptions\fR] \-\-rev [\fIrev\fR] -.Sp -.RS 4 -Supports: git, svn, hg -Run static analysis on changes to check for mistakes. If no files -are specified, lint will be run on all files which have been modified. -.IP "\fI\-\-amend\-all\fR" 4 -.IX Item "--amend-all" -.RE -.RS 4 -.Sp -.RS 4 -When linting git repositories, amend \s-1HEAD\s0 with all patches -suggested by lint without prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-amend\-autofixes\fR" 4 -.IX Item "--amend-autofixes" -.RE -.RS 4 -.Sp -.RS 4 -When linting git repositories, amend \s-1HEAD\s0 with autofix patches -suggested by lint without prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-apply\-patches\fR" 4 -.IX Item "--apply-patches" -.RE -.RS 4 -.Sp -.RS 4 -Apply patches suggested by lint to the working copy without -prompting. -.RE -.RE -.RS 4 -.IP "\fI\-\-cache\fR \fIbool\fR" 4 -.IX Item "--cache bool" -.RE -.RS 4 -.Sp -.Vb 3 -\& 0 to disable cache, 1 to enable. The default value is -\& determined by \*(Aqarc.lint.cache\*(Aq in configuration, which defaults -\& to off. See notes in \*(Aqarc.lint.cache\*(Aq. -.Ve -.IP "\fI\-\-engine\fR \fIclassname\fR" 4 -.IX Item "--engine classname" -.RE -.RS 4 -.Sp -.RS 4 -Override configured lint engine for this project. -.RE -.RE -.RS 4 -.IP "\fI\-\-everything\fR" 4 -.IX Item "--everything" -.RE -.RS 4 -.Sp -.RS 4 -Lint all files in the project. -.RE -.RE -.RS 4 -.IP "\fI\-\-lintall\fR" 4 -.IX Item "--lintall" -.RE -.RS 4 -.Sp -.RS 4 -Show all lint warnings, not just those on changed lines. When -paths are specified, this is the default behavior. -.RE -.RE -.RS 4 -.IP "\fI\-\-never\-apply\-patches\fR" 4 -.IX Item "--never-apply-patches" -.RE -.RS 4 -.Sp -.RS 4 -Never apply patches suggested by lint. -.RE -.RE -.RS 4 -.IP "\fI\-\-only\-changed\fR" 4 -.IX Item "--only-changed" -.RE -.RS 4 -.Sp -.RS 4 -Show lint warnings just on changed lines. When no paths are -specified, this is the default. This differs from only-new in -cases where line modifications introduce lint on other -unmodified lines. -.RE -.RE -.RS 4 -.IP "\fI\-\-only\-new\fR \fIbool\fR" 4 -.IX Item "--only-new bool" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Display only messages not present in the original code. -.RE -.RE -.RS 4 -.IP "\fI\-\-outfile\fR \fIpath\fR" 4 -.IX Item "--outfile path" -.RE -.RS 4 -.Sp -.RS 4 -Output the linter results to a file. Defaults to stdout. -.RE -.RE -.RS 4 -.IP "\fI\-\-output\fR \fIformat\fR" 4 -.IX Item "--output format" -.RE -.RS 4 -.Sp -.RS 4 -With 'summary', show lint warnings in a more compact format. -With 'json', show lint warnings in machine-readable \s-1JSON\s0 -format. With 'none', show no lint warnings. With 'compiler', -show lint warnings in suitable for your editor. With 'xml', -show lint warnings in the Checkstyle \s-1XML\s0 format. -.RE -.RE -.RS 4 -.IP "\fI\-\-rev\fR \fIrevision\fR" 4 -.IX Item "--rev revision" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Lint changes since a specific revision. -.RE -.RE -.RS 4 -.IP "\fI\-\-severity\fR \fIstring\fR" 4 -.IX Item "--severity string" -.RE -.RS 4 -.Sp -.RS 4 -Set minimum message severity. One of: 'advice', 'autofix', -\&'warning', 'error', 'disabled'. Defaults to 'advice'. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBlinters\fR [\fIoptions\fR] [\fIname\fR] -.Sp -.RS 4 -Supports: cli -List the available and configured linters, with information about -what they do and which versions are installed. -.Sp -if \fIname\fR is provided, the linter with that name will be displayed. -.IP "\fI\-\-search\fR \fIsearch\fR" 4 -.IX Item "--search search" -.RE -.RS 4 -.Sp -.RS 4 -Search for linters. Search is case-insensitive, and is -performedagainst name and description of each linter. -.RE -.RE -.RS 4 -.IP "\fI\-\-verbose\fR" 4 -.IX Item "--verbose" -.RE -.RS 4 -.Sp -.RS 4 -Show detailed information, including options. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBlist\fR -.Sp -.RS 4 -Supports: git, svn, hg -List your open Differential revisions. -.RE -.PP -\&\fBpaste\fR [\-\-title \fItitle\fR] [\-\-lang \fIlanguage\fR] [\-\-json] -.PP -\&\fBpaste\fR \fIid\fR [\-\-json] -.Sp -.RS 4 -Supports: text -Share and grab text using the Paste application. To create a paste, -use stdin to provide the text: -.Sp -.Vb 1 -\& $ cat list_of_ducks.txt | arc paste -.Ve -.Sp -To retrieve a paste, specify the paste \s-1ID:\s0 -.Sp -.Vb 1 -\& $ arc paste P123 -.Ve -.IP "\fI\-\-json\fR" 4 -.IX Item "--json" -.RE -.RS 4 -.Sp -.RS 4 -Output in \s-1JSON\s0 format. -.RE -.RE -.RS 4 -.IP "\fI\-\-lang\fR \fIlanguage\fR" 4 -.IX Item "--lang language" -.RE -.RS 4 -.Sp -.RS 4 -Language for syntax highlighting. -.RE -.RE -.RS 4 -.IP "\fI\-\-title\fR \fItitle\fR" 4 -.IX Item "--title title" -.RE -.RS 4 -.Sp -.RS 4 -Title for the paste. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBpatch\fR \fID12345\fR -.PP -\&\fBpatch\fR \fI\-\-revision\fR \fIrevision_id\fR -.PP -\&\fBpatch\fR \fI\-\-diff\fR \fIdiff_id\fR -.PP -\&\fBpatch\fR \fI\-\-patch\fR \fIfile\fR -.PP -\&\fBpatch\fR \fI\-\-arcbundle\fR \fIbundlefile\fR -.Sp -.RS 4 -Supports: git, svn, hg -Apply the changes in a Differential revision, patchfile, or arc -bundle to the working copy. -.IP "\fI\-\-arcbundle\fR \fIbundlefile\fR" 4 -.IX Item "--arcbundle bundlefile" -.RE -.RS 4 -.Sp -.RS 4 -Apply changes from an arc bundle generated with 'arc export'. -.RE -.RE -.RS 4 -.IP "\fI\-\-diff\fR \fIdiff_id\fR" 4 -.IX Item "--diff diff_id" -.RE -.RS 4 -.Sp -.RS 4 -Apply changes from a Differential diff. Normally you want to -use \-\-revision to get the most recent changes, but you can -specifically apply an out-of-date diff or a diff which was -never attached to a revision by using this flag. -.RE -.RE -.RS 4 -.IP "\fI\-\-encoding\fR \fIencoding\fR" 4 -.IX Item "--encoding encoding" -.RE -.RS 4 -.Sp -.RS 4 -Attempt to convert non \s-1UTF\-8\s0 patch into specified encoding. -.RE -.RE -.RS 4 -.IP "\fI\-\-force\fR" 4 -.IX Item "--force" -.RE -.RS 4 -.Sp -.RS 4 -Do not run any sanity checks. -.RE -.RE -.RS 4 -.IP "\fI\-\-nobranch\fR" 4 -.IX Item "--nobranch" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Normally, a new branch (git) or bookmark (hg) is created and -then the patch is applied and committed in the new -branch/bookmark. This flag cherry-picks the resultant commit -onto the original branch and deletes the temporary branch. -.RE -.RE -.RS 4 -.IP "\fI\-\-nocommit\fR" 4 -.IX Item "--nocommit" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Normally under git/hg, if the patch is successful, the changes -are committed to the working copy. This flag prevents the -commit. -.RE -.RE -.RS 4 -.IP "\fI\-\-patch\fR \fIpatchfile\fR" 4 -.IX Item "--patch patchfile" -.RE -.RS 4 -.Sp -.RS 4 -Apply changes from a git patchfile or unified patchfile. -.RE -.RE -.RS 4 -.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 -.IX Item "--revision revision_id" -.RE -.RS 4 -.Sp -.RS 4 -Apply changes from a Differential revision, using the most -recent diff that has been attached to it. You can run 'arc -patch D12345' as a shorthand. -.RE -.RE -.RS 4 -.IP "\fI\-\-skip\-dependencies\fR" 4 -.IX Item "--skip-dependencies" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Normally, if a patch has dependencies that are not present in -the working copy, arc tries to apply them as well. This flag -prevents such work. -.RE -.RE -.RS 4 -.IP "\fI\-\-update\fR" 4 -.IX Item "--update" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, svn, hg -Update the local working copy before applying the patch. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBrevert\fR -Please use arc backout instead -.PP -\&\fBset-config\fR [\fIoptions\fR] \*(-- \fIname\fR \fIvalue\fR -.Sp -.RS 4 -Supports: cli -Sets an arc configuration option. -.Sp -Options are either user (apply to all arc commands you invoke -from the current user) or local (apply only to the current working -copy). By default, user configuration is written. Use \fI\-\-local\fR -to write local configuration. -.Sp -User values are written to '~/.arcrc' on Linux and Mac \s-1OS X,\s0 and an -undisclosed location on Windows. Local values are written to an arc -directory under either .git, .hg, or .svn as appropriate. -.IP "\fI\-\-local\fR" 4 -.IX Item "--local" -.RE -.RS 4 -.Sp -.RS 4 -Set a local config value instead of a user one. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBshell-complete\fR \fI\-\-current\fR \fIN\fR \*(-- [\fIargv\fR] -.Sp -.RS 4 -Supports: bash, etc. -Implements shell completion. To use shell completion, source the -appropriate script from 'resources/shell/' in your .shellrc. -.IP "\fI\-\-current\fR \fIcursor_position\fR" 4 -.IX Item "--current cursor_position" -.RE -.RS 4 -.Sp -.RS 4 -Current term in the argument list being completed. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBstart\fR \fIobject\fR -.Sp -.RS 4 -Start tracking work in Phrequent. -.RE -.PP -\&\fBstop\fR [\-\-note \fInote\fR] [\fIobjects\fR] -.Sp -.RS 4 -Stop tracking work in Phrequent. -.IP "\fI\-\-note\fR \fInote\fR" 4 -.IX Item "--note note" -.RE -.RS 4 -.Sp -.RS 4 -A note to attach to the tracked time. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBtasks\fR [\fIoptions\fR] - View all assigned tasks. -.IP "\fI\-\-limit\fR \fIn\fR" 4 -.IX Item "--limit n" -.Sp -.RS 4 -Limit the amount of tasks outputted, default is all. -.RE -.IP "\fI\-\-order\fR \fItask_order\fR" 4 -.IX Item "--order task_order" -.Sp -.RS 4 -Arrange tasks based on priority, created, or modified, default -is priority. -.RE -.IP "\fI\-\-owner\fR \fIusername\fR" 4 -.IX Item "--owner username" -.Sp -.RS 4 -Only show tasks assigned to the given username, also accepts -\&\f(CW@all\fR to show all, default is you. -.RE -.IP "\fI\-\-status\fR \fItask_status\fR" 4 -.IX Item "--status task_status" -.Sp -.RS 4 -Show tasks that are open or closed, default is open. -.RE -.IP "\fI\-\-unassigned\fR" 4 -.IX Item "--unassigned" -.Sp -.RS 4 -Only show tasks that are not assigned (upforgrabs). -.RE -.PP -\&\fBtime\fR -.Sp -.RS 4 -Show what you're currently tracking in Phrequent. -.RE -.PP -\&\fBtodo\fR \fIsummary\fR [\fIoptions\fR] - Quickly create a task for yourself. -.IP "\fI\-\-browse\fR" 4 -.IX Item "--browse" -.Sp -.RS 4 -After creating the task, open it in a web browser. -.RE -.IP "\fI\-\-cc\fR \fIcc\fR, \fI\-C\fR \fIcc\fR" 4 -.IX Item "--cc cc, -C cc" -.Sp -.RS 4 -Other users to \s-1CC\s0 on the new task. -.RE -.IP "\fI\-\-project\fR \fIproject\fR" 4 -.IX Item "--project project" -.Sp -.RS 4 -Projects to assign to the task. -.RE -.PP -\&\fBunit\fR [\fIoptions\fR] [\fIpaths\fR] -.PP -\&\fBunit\fR [\fIoptions\fR] \-\-rev [\fIrev\fR] -.Sp -.RS 4 -Supports: git, svn, hg -Run unit tests that cover specified paths. If no paths are specified, -unit tests covering all modified files will be run. -.IP "\fI\-\-coverage\fR" 4 -.IX Item "--coverage" -.RE -.RS 4 -.Sp -.RS 4 -Always enable coverage information. -.RE -.RE -.RS 4 -.IP "\fI\-\-detailed\-coverage\fR" 4 -.IX Item "--detailed-coverage" -.RE -.RS 4 -.Sp -.RS 4 -Show a detailed coverage report on the \s-1CLI.\s0 Implies \-\-coverage. -.RE -.RE -.RS 4 -.IP "\fI\-\-engine\fR \fIclassname\fR" 4 -.IX Item "--engine classname" -.RE -.RS 4 -.Sp -.RS 4 -Override configured unit engine for this project. -.RE -.RE -.RS 4 -.IP "\fI\-\-everything\fR" 4 -.IX Item "--everything" -.RE -.RS 4 -.Sp -.RS 4 -Run every test. -.RE -.RE -.RS 4 -.IP "\fI\-\-json\fR" 4 -.IX Item "--json" -.RE -.RS 4 -.Sp -.RS 4 -Report results in \s-1JSON\s0 format. -.RE -.RE -.RS 4 -.IP "\fI\-\-no\-coverage\fR" 4 -.IX Item "--no-coverage" -.RE -.RS 4 -.Sp -.RS 4 -Always disable coverage information. -.RE -.RE -.RS 4 -.IP "\fI\-\-output\fR \fIformat\fR" 4 -.IX Item "--output format" -.RE -.RS 4 -.Sp -.RS 4 -With 'full', show full pretty report (Default). With 'json', -report results in \s-1JSON\s0 format. With 'ugly', use uglier (but -more efficient) \s-1JSON\s0 formatting. With 'none', don't print -results. -.RE -.RE -.RS 4 -.IP "\fI\-\-rev\fR \fIrevision\fR" 4 -.IX Item "--rev revision" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Run unit tests covering changes since a specific revision. -.RE -.RE -.RS 4 -.IP "\fI\-\-target\fR \fIphid\fR" 4 -.IX Item "--target phid" -.RE -.RS 4 -.Sp -.Vb 1 -\& (PROTOTYPE) Record a copy of the test results on the specified -.Ve -.Sp -.RS 4 -Harbormaster build target. -.RE -.RE -.RS 4 -.IP "\fI\-\-ugly\fR" 4 -.IX Item "--ugly" -.RE -.RS 4 -.Sp -.RS 4 -With \-\-json, use uglier (but more efficient) formatting. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBupgrade\fR -.Sp -.RS 4 -Supports: cli -Upgrade arcanist and libphutil to the latest versions. -.RE -.PP -\&\fBupload\fR \fIfile\fR [\fIfile\fR ...] [\-\-json] -.Sp -.RS 4 -Supports: filesystems -Upload a file from local disk. -.IP "\fI\-\-json\fR" 4 -.IX Item "--json" -.RE -.RS 4 -.Sp -.RS 4 -Output upload information in \s-1JSON\s0 format. -.RE -.RE -.RS 4 -.IP "\fI\-\-temporary\fR" 4 -.IX Item "--temporary" -.RE -.RS 4 -.Sp -.RS 4 -Mark the file as temporary. Temporary files will be deleted -automatically after 24 hours. -.RE -.RE -.RS 4 -.RE -.PP -\&\fBversion\fR [\fIoptions\fR] -.Sp -.RS 4 -Supports: cli -Shows the current version of arcanist. -.RE -.PP -\&\fBwhich\fR [options] (svn) -.PP -\&\fBwhich\fR [options] [\fIcommit\fR] (hg, git) -.Sp -.RS 4 -Supports: svn, git, hg -Shows which repository the current working copy corresponds to, -which commits 'arc diff' will select, and which revision is in -the working copy (or which revisions, if more than one matches). -.IP "\fI\-\-any\-status\fR" 4 -.IX Item "--any-status" -.RE -.RS 4 -.Sp -.RS 4 -Show committed and abandoned revisions. -.RE -.RE -.RS 4 -.IP "\fI\-\-base\fR \fIrules\fR" 4 -.IX Item "--base rules" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Additional rules for determining base revision. -.RE -.RE -.RS 4 -.IP "\fI\-\-head\fR \fIcommit\fR" 4 -.IX Item "--head commit" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git -Specify the end of the commit range to select. -.RE -.RE -.RS 4 -.IP "\fI\-\-show\-base\fR" 4 -.IX Item "--show-base" -.RE -.RS 4 -.Sp -.RS 4 -Supports: git, hg -Print base commit only and exit. -.RE -.RE -.RS 4 -.RE -.SH "OPTION REFERENCE" -.IX Header "OPTION REFERENCE" -.IP "\fI\-\-trace\fR" 4 -.IX Item "--trace" -.PP -Debugging command. Shows underlying commands as they are executed, -and full stack traces when exceptions are thrown. -.IP "\fI\-\-no\-ansi\fR" 4 -.IX Item "--no-ansi" -.PP -Output in plain \s-1ASCII\s0 text only, without color or style. -.IP "\fI\-\-ansi\fR" 4 -.IX Item "--ansi" -.PP -Use formatting even in environments which probably don't support it. -Example: arc \-\-ansi unit | less \-r -.IP "\fI\-\-load\-phutil\-library=/path/to/library\fR" 4 -.IX Item "--load-phutil-library=/path/to/library" -.PP -Ignore libraries listed in .arcconfig and explicitly load specified -libraries instead. Mostly useful for Arcanist development. -.IP "\fI\-\-conduit\-uri\fR \fIuri\fR" 4 -.IX Item "--conduit-uri uri" -.PP -Ignore configured Conduit \s-1URI\s0 and use an explicit one instead. Mostly -useful for Arcanist development. -.IP "\fI\-\-conduit\-token\fR \fItoken\fR" 4 -.IX Item "--conduit-token token" -.PP -Ignore configured credentials and use an explicit \s-1API\s0 token instead. -.IP "\fI\-\-conduit\-version\fR \fIversion\fR" 4 -.IX Item "--conduit-version version" -.PP -Ignore software version and claim to be running some other version -instead. Mostly useful for Arcanist development. May cause bad things -to happen. -.IP "\fI\-\-conduit\-timeout\fR \fItimeout\fR" 4 -.IX Item "--conduit-timeout timeout" -.PP -Override the default Conduit timeout. Specified in seconds. -.IP "\fI\-\-config\fR \fIkey=value\fR" 4 -.IX Item "--config key=value" -.PP -Specify a runtime configuration value. This will take precedence -over static values, and only affect the current arcanist invocation. -.IP "\fI\-\-skip\-arcconfig\fR" 4 -.IX Item "--skip-arcconfig" -.PP -Skip the working copy configuration file -.IP "\fI\-\-arcrc\-file\fR \fIfilename\fR" 4 -.IX Item "--arcrc-file filename" -.PP -Use provided file instead of ~/.arcrc. diff -Nru phabricator-0~git20200925/debian/arcanist.links phabricator-0~git20220903/debian/arcanist.links --- phabricator-0~git20200925/debian/arcanist.links 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/arcanist.links 2022-09-08 09:46:51.000000000 +0000 @@ -1,2 +1,2 @@ -usr/share/arcanist/bin/arc usr/bin/arc +usr/share/arcanist/bin/arc usr/bin/arcanist diff -Nru phabricator-0~git20200925/debian/arcanist.manpages phabricator-0~git20220903/debian/arcanist.manpages --- phabricator-0~git20200925/debian/arcanist.manpages 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/arcanist.manpages 2022-09-08 09:46:51.000000000 +0000 @@ -1 +1 @@ -debian/arc.1 +debian/doc/arcanist.1 diff -Nru phabricator-0~git20200925/debian/arcanist.postinst phabricator-0~git20220903/debian/arcanist.postinst --- phabricator-0~git20200925/debian/arcanist.postinst 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/arcanist.postinst 2022-09-08 13:05:07.000000000 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh + +set -e + +. /usr/share/debconf/confmodule + +case "$1" in + configure) + if dpkg --compare-versions "$2" 'lt' '0~git20220903~'; then + db_input critical arcanist/namechange || true + db_go + fi + ;; + + abort-upgrade | abort-remove | abort-deconfigure) ;; + + *) + echo "postinst called with unknown argument '$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# +exit 0 diff -Nru phabricator-0~git20200925/debian/arcanist.templates phabricator-0~git20220903/debian/arcanist.templates --- phabricator-0~git20200925/debian/arcanist.templates 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/arcanist.templates 2022-09-08 09:46:51.000000000 +0000 @@ -0,0 +1,9 @@ +Template: arcanist/namechange +Type: note +_Description: Name of the arc binary has changed + Due to a file name collision, the name of the management binary + /usr/bin/arc has been changed to /usr/bin/arcanist. + . + Please either change any application to use that new name, or add + "/usr/share/arcanist/bin/" to the PATH environment variable. The + program is still available as "arc" there. diff -Nru phabricator-0~git20200925/debian/arc.cat1 phabricator-0~git20220903/debian/arc.cat1 --- phabricator-0~git20200925/debian/arc.cat1 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/arc.cat1 1970-01-01 00:00:00.000000000 +0000 @@ -1,1002 +0,0 @@ -NAME - arc - arcanist, a code review and revision management utility - -SYNOPSIS - arc command [options] [args] - This help file provides a detailed command reference. - -COMMAND REFERENCE - - alias - alias command - alias command target -- [options] - Supports: cli - Create an alias from command to target (optionally, with - options). For example: - - arc alias fpatch patch -- --force - - ...will create a new 'arc' command, 'arc fpatch', which invokes - 'arc patch --force ...' when run. NOTE: use "--" before specifying - options! - - If you start an alias with "!", the remainder of the alias will be - invoked as a shell command. For example, if you want to implement - 'arc ls', you can do so like this: - - arc alias ls '!ls' - - You can now run "arc ls" and it will behave like "ls". Of course, this - example is silly and would make your life worse. - - You can not overwrite builtins, including 'alias' itself. The builtin - will always execute, even if it was added after your alias. - - To remove an alias, run: - - arc alias fpatch - - Without any arguments, 'arc alias' will list aliases. - - - amend [--revision revision_id] [--show] - Supports: git, hg - Amend the working copy, synchronizing the local commit message from - Differential. - - Supported in Mercurial 2.2 and newer. - - --revision revision_id - Use the message from a specific revision. If you do not specify - a revision, arc will guess which revision is in the working - copy. - - --show - Show the amended commit message, without modifying the working - copy. - - - anoid - There's only one way to find out... - - - backout - Reverts/backouts on a previous commit. Supports: git, hg - Command is used like this: arc backout | - Entering a differential revision will only work if there is only one commit - associated with the revision. This requires your working copy is up to date - and that the commit exists in the working copy. - - - bookmark [options] - bookmark name [start] - Supports: hg - Alias for arc feature. - - --by-status - Sort branches by status instead of time. - - --output format - With 'json', show features in machine-readable JSON format. - - --view-all - Include closed and abandoned revisions. - - - branch [options] - branch name [start] - Supports: git - Alias for arc feature. - - --by-status - Sort branches by status instead of time. - - --output format - With 'json', show features in machine-readable JSON format. - - --view-all - Include closed and abandoned revisions. - - - browse [options] path ... - browse [options] object ... - Supports: git, hg, svn - Open a file or object (like a task or revision) in your web browser. - - $ arc browse README # Open a file in Diffusion. - $ arc browse T123 # View a task. - $ arc browse HEAD # View a symbolic commit. - - Set the 'browser' value using 'arc set-config' to select a browser. If - no browser is set, the command will try to guess which browser to use. - - --branch branch_name - Default branch name to view on server. Defaults to "master". - - --force - Open arguments as paths, even if they do not exist in the - working copy. - - - call-conduit method - Supports: http, https - Allows you to make a raw Conduit method call: - - - Run this command from a working directory. - - Call parameters are REQUIRED and read as a JSON blob from stdin. - - Results are written to stdout as a JSON blob. - - This workflow is primarily useful for writing scripts which integrate - with Phabricator. Examples: - - $ echo '{}' | arc call-conduit conduit.ping - $ echo '{"phid":"PHID-FILE-xxxx"}' | arc call-conduit file.download - - - close task_id [options] - Close a task or otherwise update its status. - - --list-statuses - Show available status options and exit. - - --message comment, -m comment - Provide a comment with your status change. - - --status status, -s status - Specify a new status. Valid status options can be seen with the - `list-statuses` argument. - - - close-revision [options] revision - Supports: git, hg, svn - Close a revision which has been committed (svn) or pushed (git, hg). - You should not normally need to do this: arc commit (svn), arc amend - (git, hg), arc land (git, hg), or repository tracking on the master - remote repository should do it for you. However, if these mechanisms - have failed for some reason you can use this command to manually - change a revision status from "Accepted" to "Closed". - - --finalize - Close only if the repository is untracked and the revision is - accepted. Continue even if the close can't happen. This is a - soft version of '' used by other workflows. - - --quiet - Do not print a success message. - - - commit [--revision revision_id] [--show] - Supports: svn - Commit a revision which has been accepted by a reviewer. - - --revision revision_id - Commit a specific revision. If you do not specify a revision, - arc will look for committable revisions. - - --show - Show the command which would be issued, but do not actually - commit anything. - - - cover [--rev revision] [path ...] - Supports: svn, git, hg - Cover your... professional reputation. Show blame for the lines you - changed in your working copy (svn) or since some commit (hg, git). - This will take a minute because blame takes a minute, especially under - SVN. - - --rev revision - Supports: git, hg - Cover changes since a specific revision. - - - diff [paths] (svn) - diff [commit] (git, hg) - Supports: git, svn, hg - Generate a Differential diff or revision from local changes. - - Under git and mercurial, you can specify a commit (like HEAD^^^ - or master) and Differential will generate a diff against the - merge base of that commit and your current working directory parent. - - Under svn, you can choose to include only some of the modified files - in the working copy in the diff by specifying their paths. If you - omit paths, all changes are included in the diff. - - --add-all, -a - Automatically add all unstaged and uncommitted files to the - commit. - - --advice - Require excuse for lint advice in addition to lint warnings and - errors. - - --allow-untracked - Skip checks for untracked files in the working copy. - - --amend-all - When linting git repositories, amend HEAD with all patches - suggested by lint without prompting. - - --amend-autofixes - When linting git repositories, amend HEAD with autofix patches - suggested by lint without prompting. - - --apply-patches - Apply patches suggested by lint to the working copy without - prompting. - - --base rules - Supports: git, hg - Additional rules for determining base revision. - - --browse - After creating a diff or revision, open it in a web browser. - - --cache bool - 0 to disable lint cache, 1 to enable (default). - - --cc usernames - When creating a revision, add CCs. - - --coverage - Always enable coverage information. - - --create - Always create a new revision. - - --edit - Supports: git, hg - When updating a revision under git, edit revision information - before updating. - - --encoding encoding - Attempt to convert non UTF-8 hunks into specified encoding. - - --excuse excuse - Provide a prepared in advance excuse for any lints/tests shall - they fail. - - --head commit - Supports: git - Specify the end of the commit range. This disables many - Arcanist/Phabricator features which depend on having access to - the working copy. - - --ignore-unsound-tests - Ignore unsound test failures without prompting. - - --json - Emit machine-readable JSON. EXPERIMENTAL! Probably does not - work! - - --less-context - Normally, files are diffed with full context: the entire file - is sent to Differential so reviewers can 'show more' and see - it. If you are making changes to very large files with tens of - thousands of lines, this may not work well. With this flag, a - diff will be created that has only a few lines of context. - - --lintall - Raise all lint warnings, not just those on lines you changed. - - --message message, -m message - When updating a revision, use the specified message instead of - prompting. - - --message-file file, -F file - When creating a revision, read revision information from this - file. - - --never-apply-patches - Never apply patches suggested by lint. - - --no-amend - Never amend commits in the working copy with lint patches. - - --no-coverage - Always disable coverage information. - - --no-diff - Only run lint and unit tests. Intended for internal use. - - --nolint - Do not run lint. - - --nounit - Do not run unit tests. - - --only - Only generate a diff, without running lint, unit tests, or - other auxiliary steps. See also --preview. - - --only-new bool - Display only lint messages not present in the original code. - - --plan-changes - Create or update a revision without requesting a code review. - - --preview - Instead of creating or updating a revision, only create a diff, - which you may later attach to a revision. This still runs lint - unit tests. See also --only. - - --raw - Read diff from stdin, not from the working copy. This disables - many Arcanist/Phabricator features which depend on having - access to the working copy. - - --raw-command command - Generate diff by executing a specified command, not from the - working copy. This disables many Arcanist/Phabricator features - which depend on having access to the working copy. - - --reviewers usernames - When creating a revision, add reviewers. - - --skip-binaries - Do not upload binaries (like images). - - --skip-staging - Do not copy changes to the staging area. - - --uncommitted - Supports: hg - Suppress warning about uncommitted changes. - - --update revision_id - Always update a specific revision. - - --use-commit-message commit, -C commit - Supports: git - Read revision information from a specific commit. - - --verbatim - Supports: hg, git - When creating a revision, try to use the working copy commit - message verbatim, without prompting to edit it. When updating a - revision, update some fields from the local commit message. - - - download file [--as name] [--show] - Supports: filesystems - Download a file to local disk, e.g.: - - $ arc download F33 # Download file 'F33' - - --as name - Save the file with a specific name rather than the default. - - --show - Write file to stdout instead of to disk. - - - export [paths] format (svn) - export [commit_range] format (git, hg) - export --revision revision_id format - export --diff diff_id format - Supports: svn, git, hg - Export the local changeset (or a Differential changeset) to a file, - in some format: git diff (--git), unified diff - (--unified), or arc bundle (--arcbundle path) format. - - --arcbundle file - Export change as an arc bundle. This format can represent all - changes. These bundles can be applied with 'arc patch'. - - --diff diff_id - Instead of exporting changes from the working copy, export them - from a Differential diff. - - --encoding encoding - Attempt to convert non UTF-8 patch into specified encoding. - - --git - Export change as a git patch. This format is more complete than - unified, but less complete than arc bundles. These patches can - be applied with 'git apply' or 'arc patch'. - - --revision revision_id - Instead of exporting changes from the working copy, export them - from a Differential revision. - - --unified - Export change as a unified patch. This format is less complete - than git patches or arc bundles. These patches can be applied - with 'patch' or 'arc patch'. - - - feature [options] - feature name [start] - Supports: git, hg - A wrapper on 'git branch' or 'hg bookmark'. - - Without name, it lists the available branches and their revision - status. - - With name, it creates or checks out a branch. If the branch - name doesn't exist and is in format D123 then the branch of - revision D123 is checked out. Use start to specify where the new - branch will start. Use 'arc.feature.start.default' to set the default - feature start location. - - --by-status - Sort branches by status instead of time. - - --output format - With 'json', show features in machine-readable JSON format. - - --view-all - Include closed and abandoned revisions. - - - flag [object ...] - flag object --clear - flag object [--edit] [--color color] [--note note] - In the first form, list objects you've flagged. You can provide the - names of one or more objects (Maniphest tasks T#, Differential - revisions D#, Diffusion references rXXX???, or PHIDs PHID-XXX-???) - to print only flags for those objects. - - In the second form, clear an existing flag on one object. - - In the third form, create or update a flag on one object. Color - defaults to blue and note to empty, but if you omit both you must - pass --edit. - - --clear - Delete the flag on an object. - - --color color - Set the color of a flag. - - --edit - Edit the flag on an object. - - --note note - Set the note on a flag. - - - get-config [options] -- [name ...] - Supports: cli - Reads an arc configuration option. With no argument, reads all - options. - - With --verbose, shows detailed information about one or more - options. - - --verbose - Show detailed information about options. - - - help [command] - help --full - Supports: english - Shows this help. With command, shows help about a specific - command. - - --full - Print detailed information about each command. - - - install-certificate [uri] - Supports: http, https - Installs Conduit credentials into your ~/.arcrc for the given install - of Phabricator. You need to do this before you can use 'arc', as it - enables 'arc' to link your command-line activity with your account on - the web. Run this command from within a project directory to install - that project's certificate, or specify an explicit URI (like - "https://phabricator.example.com/"). - - - land [options] [ref] - Supports: git, hg - - Publish an accepted revision after review. This command is the last - step in the standard Differential pre-publish code review workflow. - - This command merges and pushes changes associated with an accepted - revision that are currently sitting in ref, which is usually the - name of a local branch. Without ref, the current working copy - state will be used. - - Under Git: branches, tags, and arbitrary commits (detached HEADs) - may be landed. - - Under Mercurial: branches and bookmarks may be landed, but only - onto a target of the same type. See T3855. - - The workflow selects a target branch to land onto and a remote where - the change will be pushed to. - - A target branch is selected by examining these sources in order: - - - the --onto flag; - - the upstream of the current branch, recursively (Git only); - - the arc.land.onto.default configuration setting; - - or by falling back to a standard default: - - "master" in Git; - - "default" in Mercurial. - - A remote is selected by examining these sources in order: - - - the --remote flag; - - the upstream of the current branch, recursively (Git only); - - or by falling back to a standard default: - - "origin" in Git; - - the default remote in Mercurial. - - After selecting a target branch and a remote, the commits which will - be landed are printed. - - With --preview, execution stops here, before the change is - merged. - - The change is merged with the changes in the target branch, - following these rules: - - In repositories with mutable history or with --squash, this will - perform a squash merge (the entire branch will be represented as one - commit after the merge). - - In repositories with immutable history or with --merge, this will - perform a strict merge (a merge commit will always be created, and - local commits will be preserved). - - The resulting commit will be given an up-to-date commit message - describing the final state of the revision in Differential. - - In Git, the merge occurs in a detached HEAD. The local branch - reference (if one exists) is not updated yet. - - With --hold, execution stops here, before the change is pushed. - - The change is pushed into the remote. - - Consulting mystical sources of power, the workflow makes a guess - about what state you wanted to end up in after the process finishes - and the working copy is put into that state. - - The branch which was landed is deleted, unless the --keep-branch - flag was passed or the landing branch is the same as the target - branch. - - - --delete-remote - Delete the feature branch in the remote after landing it. - - --hold - Prepare the change to be pushed, but do not actually push it. - - --keep-branch - Keep the feature branch after pushing changes to the remote (by - default, it is deleted). - - --merge - Supports: git - Perform a --no-ff merge, not a --squash merge. If the project - is marked as having an immutable history, this is the default - behavior. - - --onto master - Land feature branch onto a branch other than the default - ('master' in git, 'default' in hg). You can change the default - by setting 'arc.land.onto.default' with `arc set-config` or for - the entire project in .arcconfig. - - --preview - Prints the commits that would be landed. Does not actually - modify or land the commits. - - --remote origin - Push to a remote other than the default ('origin' in git). - - --revision id - Use the message from a specific revision, rather than inferring - the revision based on branch content. - - --squash - Perform a --squash merge, not a --no-ff merge. If the project - is marked as having a mutable history, this is the default - behavior. - - --update-with-merge - Supports: git - When updating the feature branch, use merge instead of rebase. - This is the default behavior. Setting arc.land.update.default - to 'merge' can also be used to make this the default. - - --update-with-rebase - Supports: git - When updating the feature branch, use rebase instead of merge. - This might make things work better in some cases. Set - arc.land.update.default to 'rebase' to make this the default. - - - liberate [path] - Supports: libphutil - Create or update a libphutil library, generating required metadata - files like init.php. - - --all - Drop the module cache before liberating. This will completely - reanalyze the entire library. Thorough, but slow! - - --force-update - Force the library map to be updated, even in the presence of - lint errors. - - --library-name name - Use a flag for library name rather than awaiting user input. - - - lint [options] [paths] - lint [options] --rev [rev] - Supports: git, svn, hg - Run static analysis on changes to check for mistakes. If no files - are specified, lint will be run on all files which have been modified. - - --amend-all - When linting git repositories, amend HEAD with all patches - suggested by lint without prompting. - - --amend-autofixes - When linting git repositories, amend HEAD with autofix patches - suggested by lint without prompting. - - --apply-patches - Apply patches suggested by lint to the working copy without - prompting. - - --cache bool - 0 to disable cache, 1 to enable. The default value is - determined by 'arc.lint.cache' in configuration, which defaults - to off. See notes in 'arc.lint.cache'. - - --engine classname - Override configured lint engine for this project. - - --everything - Lint all files in the project. - - --lintall - Show all lint warnings, not just those on changed lines. When - paths are specified, this is the default behavior. - - --never-apply-patches - Never apply patches suggested by lint. - - --only-changed - Show lint warnings just on changed lines. When no paths are - specified, this is the default. This differs from only-new in - cases where line modifications introduce lint on other - unmodified lines. - - --only-new bool - Supports: git, hg - Display only messages not present in the original code. - - --outfile path - Output the linter results to a file. Defaults to stdout. - - --output format - With 'summary', show lint warnings in a more compact format. - With 'json', show lint warnings in machine-readable JSON - format. With 'none', show no lint warnings. With 'compiler', - show lint warnings in suitable for your editor. With 'xml', - show lint warnings in the Checkstyle XML format. - - --rev revision - Supports: git, hg - Lint changes since a specific revision. - - --severity string - Set minimum message severity. One of: 'advice', 'autofix', - 'warning', 'error', 'disabled'. Defaults to 'advice'. - - - linters [options] [name] - Supports: cli - List the available and configured linters, with information about - what they do and which versions are installed. - - if name is provided, the linter with that name will be displayed. - - --search search - Search for linters. Search is case-insensitive, and is - performedagainst name and description of each linter. - - --verbose - Show detailed information, including options. - - - list - Supports: git, svn, hg - List your open Differential revisions. - - - paste [--title title] [--lang language] [--json] - paste id [--json] - Supports: text - Share and grab text using the Paste application. To create a paste, - use stdin to provide the text: - - $ cat list_of_ducks.txt | arc paste - - To retrieve a paste, specify the paste ID: - - $ arc paste P123 - - --json - Output in JSON format. - - --lang language - Language for syntax highlighting. - - --title title - Title for the paste. - - - patch D12345 - patch --revision revision_id - patch --diff diff_id - patch --patch file - patch --arcbundle bundlefile - Supports: git, svn, hg - Apply the changes in a Differential revision, patchfile, or arc - bundle to the working copy. - - --arcbundle bundlefile - Apply changes from an arc bundle generated with 'arc export'. - - --diff diff_id - Apply changes from a Differential diff. Normally you want to - use --revision to get the most recent changes, but you can - specifically apply an out-of-date diff or a diff which was - never attached to a revision by using this flag. - - --encoding encoding - Attempt to convert non UTF-8 patch into specified encoding. - - --force - Do not run any sanity checks. - - --nobranch - Supports: git, hg - Normally, a new branch (git) or bookmark (hg) is created and - then the patch is applied and committed in the new - branch/bookmark. This flag cherry-picks the resultant commit - onto the original branch and deletes the temporary branch. - - --nocommit - Supports: git, hg - Normally under git/hg, if the patch is successful, the changes - are committed to the working copy. This flag prevents the - commit. - - --patch patchfile - Apply changes from a git patchfile or unified patchfile. - - --revision revision_id - Apply changes from a Differential revision, using the most - recent diff that has been attached to it. You can run 'arc - patch D12345' as a shorthand. - - --skip-dependencies - Supports: git, hg - Normally, if a patch has dependencies that are not present in - the working copy, arc tries to apply them as well. This flag - prevents such work. - - --update - Supports: git, svn, hg - Update the local working copy before applying the patch. - - - revert - Please use arc backout instead - - - set-config [options] -- name value - Supports: cli - Sets an arc configuration option. - - Options are either user (apply to all arc commands you invoke - from the current user) or local (apply only to the current working - copy). By default, user configuration is written. Use --local - to write local configuration. - - User values are written to '~/.arcrc' on Linux and Mac OS X, and an - undisclosed location on Windows. Local values are written to an arc - directory under either .git, .hg, or .svn as appropriate. - - --local - Set a local config value instead of a user one. - - - shell-complete --current N -- [argv] - Supports: bash, etc. - Implements shell completion. To use shell completion, source the - appropriate script from 'resources/shell/' in your .shellrc. - - --current cursor_position - Current term in the argument list being completed. - - - start object - Start tracking work in Phrequent. - - - stop [--note note] [objects] - Stop tracking work in Phrequent. - - --note note - A note to attach to the tracked time. - - - tasks [options] - View all assigned tasks. - - --limit n - Limit the amount of tasks outputted, default is all. - - --order task_order - Arrange tasks based on priority, created, or modified, default - is priority. - - --owner username - Only show tasks assigned to the given username, also accepts - @all to show all, default is you. - - --status task_status - Show tasks that are open or closed, default is open. - - --unassigned - Only show tasks that are not assigned (upforgrabs). - - - time - Show what you're currently tracking in Phrequent. - - - todo summary [options] - Quickly create a task for yourself. - - --browse - After creating the task, open it in a web browser. - - --cc cc, -C cc - Other users to CC on the new task. - - --project project - Projects to assign to the task. - - - unit [options] [paths] - unit [options] --rev [rev] - Supports: git, svn, hg - Run unit tests that cover specified paths. If no paths are specified, - unit tests covering all modified files will be run. - - --coverage - Always enable coverage information. - - --detailed-coverage - Show a detailed coverage report on the CLI. Implies --coverage. - - --engine classname - Override configured unit engine for this project. - - --everything - Run every test. - - --json - Report results in JSON format. - - --no-coverage - Always disable coverage information. - - --output format - With 'full', show full pretty report (Default). With 'json', - report results in JSON format. With 'ugly', use uglier (but - more efficient) JSON formatting. With 'none', don't print - results. - - --rev revision - Supports: git, hg - Run unit tests covering changes since a specific revision. - - --target phid - (PROTOTYPE) Record a copy of the test results on the specified - Harbormaster build target. - - --ugly - With --json, use uglier (but more efficient) formatting. - - - upgrade - Supports: cli - Upgrade arcanist and libphutil to the latest versions. - - - upload file [file ...] [--json] - Supports: filesystems - Upload a file from local disk. - - --json - Output upload information in JSON format. - - --temporary - Mark the file as temporary. Temporary files will be deleted - automatically after 24 hours. - - - version [options] - Supports: cli - Shows the current version of arcanist. - - - which [options] (svn) - which [options] [commit] (hg, git) - Supports: svn, git, hg - Shows which repository the current working copy corresponds to, - which commits 'arc diff' will select, and which revision is in - the working copy (or which revisions, if more than one matches). - - --any-status - Show committed and abandoned revisions. - - --base rules - Supports: git, hg - Additional rules for determining base revision. - - --head commit - Supports: git - Specify the end of the commit range to select. - - --show-base - Supports: git, hg - Print base commit only and exit. - - -OPTION REFERENCE - - --trace - Debugging command. Shows underlying commands as they are executed, - and full stack traces when exceptions are thrown. - - --no-ansi - Output in plain ASCII text only, without color or style. - - --ansi - Use formatting even in environments which probably don't support it. - Example: arc --ansi unit | less -r - - --load-phutil-library=/path/to/library - Ignore libraries listed in .arcconfig and explicitly load specified - libraries instead. Mostly useful for Arcanist development. - - --conduit-uri uri - Ignore configured Conduit URI and use an explicit one instead. Mostly - useful for Arcanist development. - - --conduit-token token - Ignore configured credentials and use an explicit API token instead. - - --conduit-version version - Ignore software version and claim to be running some other version - instead. Mostly useful for Arcanist development. May cause bad things - to happen. - - --conduit-timeout timeout - Override the default Conduit timeout. Specified in seconds. - - --config key=value - Specify a runtime configuration value. This will take precedence - over static values, and only affect the current arcanist invocation. - - --skip-arcconfig - Skip the working copy configuration file - - --arcrc-file filename - Use provided file instead of ~/.arcrc. diff -Nru phabricator-0~git20200925/debian/arc.pod phabricator-0~git20220903/debian/arc.pod --- phabricator-0~git20200925/debian/arc.pod 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/arc.pod 1970-01-01 00:00:00.000000000 +0000 @@ -1,2884 +0,0 @@ - -=head1 NAME - - -B - arcanist, a code review and revision management utility - - -=head1 SYNOPSIS - - -B I [I] [I] -This help file provides a detailed command reference. - - -=head1 COMMAND REFERENCE - - - -B - -B I - -B I I -- [I] - -=over - -Supports: cli -Create an alias from I to I (optionally, with -I). For example: - - arc alias fpatch patch -- --force - -...will create a new 'arc' command, 'arc fpatch', which invokes -'arc patch --force ...' when run. NOTE: use "--" before specifying -options! - -If you start an alias with "!", the remainder of the alias will be -invoked as a shell command. For example, if you want to implement -'arc ls', you can do so like this: - - arc alias ls '!ls' - -You can now run "arc ls" and it will behave like "ls". Of course, this -example is silly and would make your life worse. - -You can not overwrite builtins, including 'alias' itself. The builtin -will always execute, even if it was added after your alias. - -To remove an alias, run: - - arc alias fpatch - -Without any arguments, 'arc alias' will list aliases. - - -=back - -B [--revision I] [--show] - -=over - -Supports: git, hg -Amend the working copy, synchronizing the local commit message from -Differential. - -Supported in Mercurial 2.2 and newer. - - -=over - -=item I<--revision> I - -=back - - -=over - -Use the message from a specific revision. If you do not specify -a revision, arc will guess which revision is in the working -copy. - -=back - - -=over - -=item I<--show> - -=back - - -=over - -Show the amended commit message, without modifying the working -copy. - -=back - - -=back - -B - -=over - -There's only one way to find out... - - -=back - -B - -=over - -Reverts/backouts on a previous commit. Supports: git, hg - -=over - -Command is used like this: arc backout | -Entering a differential revision will only work if there is only one commit -associated with the revision. This requires your working copy is up to date -and that the commit exists in the working copy. - -=back - - -=back - -B [I] - -B I [I] - -=over - -Supports: hg -Alias for arc feature. - - -=over - -=item I<--by-status> - -=back - - -=over - -Sort branches by status instead of time. - -=back - - -=over - -=item I<--output> I - -=back - - -=over - -With 'json', show features in machine-readable JSON format. - -=back - - -=over - -=item I<--view-all> - -=back - - -=over - -Include closed and abandoned revisions. - -=back - - -=back - -B [I] - -B I [I] - -=over - -Supports: git -Alias for arc feature. - - -=over - -=item I<--by-status> - -=back - - -=over - -Sort branches by status instead of time. - -=back - - -=over - -=item I<--output> I - -=back - - -=over - -With 'json', show features in machine-readable JSON format. - -=back - - -=over - -=item I<--view-all> - -=back - - -=over - -Include closed and abandoned revisions. - -=back - - -=back - -B [I] I ... - -B [I] I ... - -=over - -Supports: git, hg, svn -Open a file or object (like a task or revision) in your web browser. - - $ arc browse README # Open a file in Diffusion. - $ arc browse T123 # View a task. - $ arc browse HEAD # View a symbolic commit. - -Set the 'browser' value using 'arc set-config' to select a browser. If -no browser is set, the command will try to guess which browser to use. - - -=over - -=item I<--branch> I - -=back - - -=over - -Default branch name to view on server. Defaults to "master". - -=back - - -=over - -=item I<--force> - -=back - - -=over - -Open arguments as paths, even if they do not exist in the -working copy. - -=back - - -=back - -B I - -=over - -Supports: http, https -Allows you to make a raw Conduit method call: - - - Run this command from a working directory. - - Call parameters are REQUIRED and read as a JSON blob from stdin. - - Results are written to stdout as a JSON blob. - -This workflow is primarily useful for writing scripts which integrate -with Phabricator. Examples: - - $ echo '{}' | arc call-conduit conduit.ping - $ echo '{"phid":"PHID-FILE-xxxx"}' | arc call-conduit file.download - - -=back - -B I [I] - Close a task or otherwise update its status. - - -=over - -=item I<--list-statuses> - -=back - - -=over - -Show available status options and exit. - -=back - - -=over - -=item I<--message> I, I<-m> I - -=back - - -=over - -Provide a comment with your status change. - -=back - - -=over - -=item I<--status> I, I<-s> I - -=back - - -=over - -Specify a new status. Valid status options can be seen with the -`list-statuses` argument. - -=back - - - -B [I] I - -=over - -Supports: git, hg, svn -Close a revision which has been committed (svn) or pushed (git, hg). -You should not normally need to do this: arc commit (svn), arc amend -(git, hg), arc land (git, hg), or repository tracking on the master -remote repository should do it for you. However, if these mechanisms -have failed for some reason you can use this command to manually -change a revision status from "Accepted" to "Closed". - - -=over - -=item I<--finalize> - -=back - - -=over - -Close only if the repository is untracked and the revision is -accepted. Continue even if the close can't happen. This is a -soft version of '' used by other workflows. - -=back - - -=over - -=item I<--quiet> - -=back - - -=over - -Do not print a success message. - -=back - - -=back - -B [--revision I] [--show] - -=over - -Supports: svn -Commit a revision which has been accepted by a reviewer. - - -=over - -=item I<--revision> I - -=back - - -=over - -Commit a specific revision. If you do not specify a revision, -arc will look for committable revisions. - -=back - - -=over - -=item I<--show> - -=back - - -=over - -Show the command which would be issued, but do not actually -commit anything. - -=back - - -=back - -B [--rev I] [I ...] - -=over - -Supports: svn, git, hg -Cover your... professional reputation. Show blame for the lines you -changed in your working copy (svn) or since some commit (hg, git). -This will take a minute because blame takes a minute, especially under -SVN. - - -=over - -=item I<--rev> I - -=back - - -=over - -Supports: git, hg -Cover changes since a specific revision. - -=back - - -=back - -B [I] (svn) - -B [I] (git, hg) - -=over - -Supports: git, svn, hg -Generate a Differential diff or revision from local changes. - -Under git and mercurial, you can specify a commit (like I -or I) and Differential will generate a diff against the -merge base of that commit and your current working directory parent. - -Under svn, you can choose to include only some of the modified files -in the working copy in the diff by specifying their paths. If you -omit paths, all changes are included in the diff. - - -=over - -=item I<--add-all>, I<-a> - -=back - - -=over - -Automatically add all unstaged and uncommitted files to the -commit. - -=back - - -=over - -=item I<--advice> - -=back - - -=over - -Require excuse for lint advice in addition to lint warnings and -errors. - -=back - - -=over - -=item I<--allow-untracked> - -=back - - -=over - -Skip checks for untracked files in the working copy. - -=back - - -=over - -=item I<--amend-all> - -=back - - -=over - -When linting git repositories, amend HEAD with all patches -suggested by lint without prompting. - -=back - - -=over - -=item I<--amend-autofixes> - -=back - - -=over - -When linting git repositories, amend HEAD with autofix patches -suggested by lint without prompting. - -=back - - -=over - -=item I<--apply-patches> - -=back - - -=over - -Apply patches suggested by lint to the working copy without -prompting. - -=back - - -=over - -=item I<--base> I - -=back - - -=over - -Supports: git, hg -Additional rules for determining base revision. - -=back - - -=over - -=item I<--browse> - -=back - - -=over - -After creating a diff or revision, open it in a web browser. - -=back - - -=over - -=item I<--cache> I - -=back - - 0 to disable lint cache, 1 to enable (default). - - -=over - -=item I<--cc> I - -=back - - -=over - -When creating a revision, add CCs. - -=back - - -=over - -=item I<--coverage> - -=back - - -=over - -Always enable coverage information. - -=back - - -=over - -=item I<--create> - -=back - - -=over - -Always create a new revision. - -=back - - -=over - -=item I<--edit> - -=back - - -=over - -Supports: git, hg -When updating a revision under git, edit revision information -before updating. - -=back - - -=over - -=item I<--encoding> I - -=back - - -=over - -Attempt to convert non UTF-8 hunks into specified encoding. - -=back - - -=over - -=item I<--excuse> I - -=back - - -=over - -Provide a prepared in advance excuse for any lints/tests shall -they fail. - -=back - - -=over - -=item I<--head> I - -=back - - -=over - -Supports: git -Specify the end of the commit range. This disables many -Arcanist/Phabricator features which depend on having access to -the working copy. - -=back - - -=over - -=item I<--ignore-unsound-tests> - -=back - - -=over - -Ignore unsound test failures without prompting. - -=back - - -=over - -=item I<--json> - -=back - - -=over - -Emit machine-readable JSON. EXPERIMENTAL! Probably does not -work! - -=back - - -=over - -=item I<--less-context> - -=back - - -=over - -Normally, files are diffed with full context: the entire file -is sent to Differential so reviewers can 'show more' and see -it. If you are making changes to very large files with tens of -thousands of lines, this may not work well. With this flag, a -diff will be created that has only a few lines of context. - -=back - - -=over - -=item I<--lintall> - -=back - - -=over - -Raise all lint warnings, not just those on lines you changed. - -=back - - -=over - -=item I<--message> I, I<-m> I - -=back - - -=over - -When updating a revision, use the specified message instead of -prompting. - -=back - - -=over - -=item I<--message-file> I, I<-F> I - -=back - - -=over - -When creating a revision, read revision information from this -file. - -=back - - -=over - -=item I<--never-apply-patches> - -=back - - -=over - -Never apply patches suggested by lint. - -=back - - -=over - -=item I<--no-amend> - -=back - - -=over - -Never amend commits in the working copy with lint patches. - -=back - - -=over - -=item I<--no-coverage> - -=back - - -=over - -Always disable coverage information. - -=back - - -=over - -=item I<--no-diff> - -=back - - -=over - -Only run lint and unit tests. Intended for internal use. - -=back - - -=over - -=item I<--nolint> - -=back - - -=over - -Do not run lint. - -=back - - -=over - -=item I<--nounit> - -=back - - -=over - -Do not run unit tests. - -=back - - -=over - -=item I<--only> - -=back - - -=over - -Only generate a diff, without running lint, unit tests, or -other auxiliary steps. See also --preview. - -=back - - -=over - -=item I<--only-new> I - -=back - - -=over - -Display only lint messages not present in the original code. - -=back - - -=over - -=item I<--plan-changes> - -=back - - -=over - -Create or update a revision without requesting a code review. - -=back - - -=over - -=item I<--preview> - -=back - - -=over - -Instead of creating or updating a revision, only create a diff, -which you may later attach to a revision. This still runs lint -unit tests. See also --only. - -=back - - -=over - -=item I<--raw> - -=back - - -=over - -Read diff from stdin, not from the working copy. This disables -many Arcanist/Phabricator features which depend on having -access to the working copy. - -=back - - -=over - -=item I<--raw-command> I - -=back - - -=over - -Generate diff by executing a specified command, not from the -working copy. This disables many Arcanist/Phabricator features -which depend on having access to the working copy. - -=back - - -=over - -=item I<--reviewers> I - -=back - - -=over - -When creating a revision, add reviewers. - -=back - - -=over - -=item I<--skip-binaries> - -=back - - -=over - -Do not upload binaries (like images). - -=back - - -=over - -=item I<--skip-staging> - -=back - - -=over - -Do not copy changes to the staging area. - -=back - - -=over - -=item I<--uncommitted> - -=back - - -=over - -Supports: hg -Suppress warning about uncommitted changes. - -=back - - -=over - -=item I<--update> I - -=back - - -=over - -Always update a specific revision. - -=back - - -=over - -=item I<--use-commit-message> I, I<-C> I - -=back - - -=over - -Supports: git -Read revision information from a specific commit. - -=back - - -=over - -=item I<--verbatim> - -=back - - -=over - -Supports: hg, git -When creating a revision, try to use the working copy commit -message verbatim, without prompting to edit it. When updating a -revision, update some fields from the local commit message. - -=back - - -=back - -B I [--as I] [--show] - -=over - -Supports: filesystems -Download a file to local disk, e.g.: - - $ arc download F33 # Download file 'F33' - - -=over - -=item I<--as> I - -=back - - -=over - -Save the file with a specific name rather than the default. - -=back - - -=over - -=item I<--show> - -=back - - -=over - -Write file to stdout instead of to disk. - -=back - - -=back - -B [I] I (svn) - -B [I] I (git, hg) - -B I<--revision> I I - -B I<--diff> I I - -=over - -Supports: svn, git, hg -Export the local changeset (or a Differential changeset) to a file, -in some I: git diff (I<--git>), unified diff -(I<--unified>), or arc bundle (I<--arcbundle> I) format. - - -=over - -=item I<--arcbundle> I - -=back - - -=over - -Export change as an arc bundle. This format can represent all -changes. These bundles can be applied with 'arc patch'. - -=back - - -=over - -=item I<--diff> I - -=back - - -=over - -Instead of exporting changes from the working copy, export them -from a Differential diff. - -=back - - -=over - -=item I<--encoding> I - -=back - - -=over - -Attempt to convert non UTF-8 patch into specified encoding. - -=back - - -=over - -=item I<--git> - -=back - - -=over - -Export change as a git patch. This format is more complete than -unified, but less complete than arc bundles. These patches can -be applied with 'git apply' or 'arc patch'. - -=back - - -=over - -=item I<--revision> I - -=back - - -=over - -Instead of exporting changes from the working copy, export them -from a Differential revision. - -=back - - -=over - -=item I<--unified> - -=back - - -=over - -Export change as a unified patch. This format is less complete -than git patches or arc bundles. These patches can be applied -with 'patch' or 'arc patch'. - -=back - - -=back - -B [I] - -B I [I] - -=over - -Supports: git, hg -A wrapper on 'git branch' or 'hg bookmark'. - -Without I, it lists the available branches and their revision -status. - -With I, it creates or checks out a branch. If the branch -I doesn't exist and is in format D123 then the branch of -revision D123 is checked out. Use I to specify where the new -branch will start. Use 'arc.feature.start.default' to set the default -feature start location. - - -=over - -=item I<--by-status> - -=back - - -=over - -Sort branches by status instead of time. - -=back - - -=over - -=item I<--output> I - -=back - - -=over - -With 'json', show features in machine-readable JSON format. - -=back - - -=over - -=item I<--view-all> - -=back - - -=over - -Include closed and abandoned revisions. - -=back - - -=back - -B [I ...] - -B I --clear - -B I [--edit] [--color I] [--note I] - -=over - -In the first form, list objects you've flagged. You can provide the -names of one or more objects (Maniphest tasks T#, Differential -revisions D#, Diffusion references rXXX???, or PHIDs PHID-XXX-???) -to print only flags for those objects. - -In the second form, clear an existing flag on one object. - -In the third form, create or update a flag on one object. Color -defaults to blue and note to empty, but if you omit both you must -pass --edit. - - -=over - -=item I<--clear> - -=back - - -=over - -Delete the flag on an object. - -=back - - -=over - -=item I<--color> I - -=back - - -=over - -Set the color of a flag. - -=back - - -=over - -=item I<--edit> - -=back - - -=over - -Edit the flag on an object. - -=back - - -=over - -=item I<--note> I - -=back - - -=over - -Set the note on a flag. - -=back - - -=back - -B [I] -- [I ...] - -=over - -Supports: cli -Reads an arc configuration option. With no argument, reads all -options. - -With I<--verbose>, shows detailed information about one or more -options. - - -=over - -=item I<--verbose> - -=back - - -=over - -Show detailed information about options. - -=back - - -=back - -B [I] - -B --full - -=over - -Supports: english -Shows this help. With I, shows help about a specific -command. - - -=over - -=item I<--full> - -=back - - -=over - -Print detailed information about each command. - -=back - - -=back - -B [uri] - -=over - -Supports: http, https -Installs Conduit credentials into your ~/.arcrc for the given install -of Phabricator. You need to do this before you can use 'arc', as it -enables 'arc' to link your command-line activity with your account on -the web. Run this command from within a project directory to install -that project's certificate, or specify an explicit URI (like -"https://phabricator.example.com/"). - - -=back - -B [I] [I] - -=over - -Supports: git, hg - -Publish an accepted revision after review. This command is the last -step in the standard Differential pre-publish code review workflow. - -This command merges and pushes changes associated with an accepted -revision that are currently sitting in I, which is usually the -name of a local branch. Without I, the current working copy -state will be used. - -Under Git: branches, tags, and arbitrary commits (detached HEADs) -may be landed. - -Under Mercurial: branches and bookmarks may be landed, but only -onto a target of the same type. See T3855. - -The workflow selects a target branch to land onto and a remote where -the change will be pushed to. - -A target branch is selected by examining these sources in order: - - - the B<--onto> flag; - - the upstream of the current branch, recursively (Git only); - - the I configuration setting; - - or by falling back to a standard default: - - "master" in Git; - - "default" in Mercurial. - -A remote is selected by examining these sources in order: - - - the B<--remote> flag; - - the upstream of the current branch, recursively (Git only); - - or by falling back to a standard default: - - "origin" in Git; - - the default remote in Mercurial. - -After selecting a target branch and a remote, the commits which will -be landed are printed. - -With B<--preview>, execution stops here, before the change is -merged. - -The change is merged with the changes in the target branch, -following these rules: - -In repositories with mutable history or with B<--squash>, this will -perform a squash merge (the entire branch will be represented as one -commit after the merge). - -In repositories with immutable history or with B<--merge>, this will -perform a strict merge (a merge commit will always be created, and -local commits will be preserved). - -The resulting commit will be given an up-to-date commit message -describing the final state of the revision in Differential. - -In Git, the merge occurs in a detached HEAD. The local branch -reference (if one exists) is not updated yet. - -With B<--hold>, execution stops here, before the change is pushed. - -The change is pushed into the remote. - -Consulting mystical sources of power, the workflow makes a guess -about what state you wanted to end up in after the process finishes -and the working copy is put into that state. - -The branch which was landed is deleted, unless the B<--keep-branch> -flag was passed or the landing branch is the same as the target -branch. - - - -=over - -=item I<--delete-remote> - -=back - - -=over - -Delete the feature branch in the remote after landing it. - -=back - - -=over - -=item I<--hold> - -=back - - -=over - -Prepare the change to be pushed, but do not actually push it. - -=back - - -=over - -=item I<--keep-branch> - -=back - - -=over - -Keep the feature branch after pushing changes to the remote (by -default, it is deleted). - -=back - - -=over - -=item I<--merge> - -=back - - -=over - -Supports: git -Perform a --no-ff merge, not a --squash merge. If the project -is marked as having an immutable history, this is the default -behavior. - -=back - - -=over - -=item I<--onto> I - -=back - - -=over - -Land feature branch onto a branch other than the default -('master' in git, 'default' in hg). You can change the default -by setting 'arc.land.onto.default' with `arc set-config` or for -the entire project in .arcconfig. - -=back - - -=over - -=item I<--preview> - -=back - - -=over - -Prints the commits that would be landed. Does not actually -modify or land the commits. - -=back - - -=over - -=item I<--remote> I - -=back - - -=over - -Push to a remote other than the default ('origin' in git). - -=back - - -=over - -=item I<--revision> I - -=back - - -=over - -Use the message from a specific revision, rather than inferring -the revision based on branch content. - -=back - - -=over - -=item I<--squash> - -=back - - -=over - -Perform a --squash merge, not a --no-ff merge. If the project -is marked as having a mutable history, this is the default -behavior. - -=back - - -=over - -=item I<--update-with-merge> - -=back - - -=over - -Supports: git -When updating the feature branch, use merge instead of rebase. -This is the default behavior. Setting arc.land.update.default -to 'merge' can also be used to make this the default. - -=back - - -=over - -=item I<--update-with-rebase> - -=back - - -=over - -Supports: git -When updating the feature branch, use rebase instead of merge. -This might make things work better in some cases. Set -arc.land.update.default to 'rebase' to make this the default. - -=back - - -=back - -B [I] - -=over - -Supports: libphutil -Create or update a libphutil library, generating required metadata -files like I.php. - - -=over - -=item I<--all> - -=back - - -=over - -Drop the module cache before liberating. This will completely -reanalyze the entire library. Thorough, but slow! - -=back - - -=over - -=item I<--force-update> - -=back - - -=over - -Force the library map to be updated, even in the presence of -lint errors. - -=back - - -=over - -=item I<--library-name> I - -=back - - -=over - -Use a flag for library name rather than awaiting user input. - -=back - - -=back - -B [I] [I] - -B [I] --rev [I] - -=over - -Supports: git, svn, hg -Run static analysis on changes to check for mistakes. If no files -are specified, lint will be run on all files which have been modified. - - -=over - -=item I<--amend-all> - -=back - - -=over - -When linting git repositories, amend HEAD with all patches -suggested by lint without prompting. - -=back - - -=over - -=item I<--amend-autofixes> - -=back - - -=over - -When linting git repositories, amend HEAD with autofix patches -suggested by lint without prompting. - -=back - - -=over - -=item I<--apply-patches> - -=back - - -=over - -Apply patches suggested by lint to the working copy without -prompting. - -=back - - -=over - -=item I<--cache> I - -=back - - 0 to disable cache, 1 to enable. The default value is - determined by 'arc.lint.cache' in configuration, which defaults - to off. See notes in 'arc.lint.cache'. - - -=over - -=item I<--engine> I - -=back - - -=over - -Override configured lint engine for this project. - -=back - - -=over - -=item I<--everything> - -=back - - -=over - -Lint all files in the project. - -=back - - -=over - -=item I<--lintall> - -=back - - -=over - -Show all lint warnings, not just those on changed lines. When -paths are specified, this is the default behavior. - -=back - - -=over - -=item I<--never-apply-patches> - -=back - - -=over - -Never apply patches suggested by lint. - -=back - - -=over - -=item I<--only-changed> - -=back - - -=over - -Show lint warnings just on changed lines. When no paths are -specified, this is the default. This differs from only-new in -cases where line modifications introduce lint on other -unmodified lines. - -=back - - -=over - -=item I<--only-new> I - -=back - - -=over - -Supports: git, hg -Display only messages not present in the original code. - -=back - - -=over - -=item I<--outfile> I - -=back - - -=over - -Output the linter results to a file. Defaults to stdout. - -=back - - -=over - -=item I<--output> I - -=back - - -=over - -With 'summary', show lint warnings in a more compact format. -With 'json', show lint warnings in machine-readable JSON -format. With 'none', show no lint warnings. With 'compiler', -show lint warnings in suitable for your editor. With 'xml', -show lint warnings in the Checkstyle XML format. - -=back - - -=over - -=item I<--rev> I - -=back - - -=over - -Supports: git, hg -Lint changes since a specific revision. - -=back - - -=over - -=item I<--severity> I - -=back - - -=over - -Set minimum message severity. One of: 'advice', 'autofix', -'warning', 'error', 'disabled'. Defaults to 'advice'. - -=back - - -=back - -B [I] [I] - -=over - -Supports: cli -List the available and configured linters, with information about -what they do and which versions are installed. - -if I is provided, the linter with that name will be displayed. - - -=over - -=item I<--search> I - -=back - - -=over - -Search for linters. Search is case-insensitive, and is -performedagainst name and description of each linter. - -=back - - -=over - -=item I<--verbose> - -=back - - -=over - -Show detailed information, including options. - -=back - - -=back - -B - -=over - -Supports: git, svn, hg -List your open Differential revisions. - - -=back - -B [--title I] [--lang I<language>] [--json] - -B<paste> I<id> [--json] - -=over - -Supports: text -Share and grab text using the Paste application. To create a paste, -use stdin to provide the text: - - $ cat list_of_ducks.txt | arc paste - -To retrieve a paste, specify the paste ID: - - $ arc paste P123 - - -=over - -=item I<--json> - -=back - - -=over - -Output in JSON format. - -=back - - -=over - -=item I<--lang> I<language> - -=back - - -=over - -Language for syntax highlighting. - -=back - - -=over - -=item I<--title> I<title> - -=back - - -=over - -Title for the paste. - -=back - - -=back - -B<patch> I<D12345> - -B<patch> I<--revision> I<revision_id> - -B<patch> I<--diff> I<diff_id> - -B<patch> I<--patch> I<file> - -B<patch> I<--arcbundle> I<bundlefile> - -=over - -Supports: git, svn, hg -Apply the changes in a Differential revision, patchfile, or arc -bundle to the working copy. - - -=over - -=item I<--arcbundle> I<bundlefile> - -=back - - -=over - -Apply changes from an arc bundle generated with 'arc export'. - -=back - - -=over - -=item I<--diff> I<diff_id> - -=back - - -=over - -Apply changes from a Differential diff. Normally you want to -use --revision to get the most recent changes, but you can -specifically apply an out-of-date diff or a diff which was -never attached to a revision by using this flag. - -=back - - -=over - -=item I<--encoding> I<encoding> - -=back - - -=over - -Attempt to convert non UTF-8 patch into specified encoding. - -=back - - -=over - -=item I<--force> - -=back - - -=over - -Do not run any sanity checks. - -=back - - -=over - -=item I<--nobranch> - -=back - - -=over - -Supports: git, hg -Normally, a new branch (git) or bookmark (hg) is created and -then the patch is applied and committed in the new -branch/bookmark. This flag cherry-picks the resultant commit -onto the original branch and deletes the temporary branch. - -=back - - -=over - -=item I<--nocommit> - -=back - - -=over - -Supports: git, hg -Normally under git/hg, if the patch is successful, the changes -are committed to the working copy. This flag prevents the -commit. - -=back - - -=over - -=item I<--patch> I<patchfile> - -=back - - -=over - -Apply changes from a git patchfile or unified patchfile. - -=back - - -=over - -=item I<--revision> I<revision_id> - -=back - - -=over - -Apply changes from a Differential revision, using the most -recent diff that has been attached to it. You can run 'arc -patch D12345' as a shorthand. - -=back - - -=over - -=item I<--skip-dependencies> - -=back - - -=over - -Supports: git, hg -Normally, if a patch has dependencies that are not present in -the working copy, arc tries to apply them as well. This flag -prevents such work. - -=back - - -=over - -=item I<--update> - -=back - - -=over - -Supports: git, svn, hg -Update the local working copy before applying the patch. - -=back - - -=back - -B<revert> -Please use arc backout instead - - - -B<set-config> [I<options>] -- I<name> I<value> - -=over - -Supports: cli -Sets an arc configuration option. - -Options are either user (apply to all arc commands you invoke -from the current user) or local (apply only to the current working -copy). By default, user configuration is written. Use I<--local> -to write local configuration. - -User values are written to '~/.arcrc' on Linux and Mac OS X, and an -undisclosed location on Windows. Local values are written to an arc -directory under either .git, .hg, or .svn as appropriate. - - -=over - -=item I<--local> - -=back - - -=over - -Set a local config value instead of a user one. - -=back - - -=back - -B<shell-complete> I<--current> I<N> -- [I<argv>] - -=over - -Supports: bash, etc. -Implements shell completion. To use shell completion, source the -appropriate script from 'resources/shell/' in your .shellrc. - - -=over - -=item I<--current> I<cursor_position> - -=back - - -=over - -Current term in the argument list being completed. - -=back - - -=back - -B<start> I<object> - -=over - -Start tracking work in Phrequent. - - -=back - -B<stop> [--note I<note>] [I<objects>] - -=over - -Stop tracking work in Phrequent. - - -=over - -=item I<--note> I<note> - -=back - - -=over - -A note to attach to the tracked time. - -=back - - -=back - -B<tasks> [I<options>] - View all assigned tasks. - - -=over - -=item I<--limit> I<n> - -=back - - -=over - -Limit the amount of tasks outputted, default is all. - -=back - - -=over - -=item I<--order> I<task_order> - -=back - - -=over - -Arrange tasks based on priority, created, or modified, default -is priority. - -=back - - -=over - -=item I<--owner> I<username> - -=back - - -=over - -Only show tasks assigned to the given username, also accepts -@all to show all, default is you. - -=back - - -=over - -=item I<--status> I<task_status> - -=back - - -=over - -Show tasks that are open or closed, default is open. - -=back - - -=over - -=item I<--unassigned> - -=back - - -=over - -Only show tasks that are not assigned (upforgrabs). - -=back - - - -B<time> - -=over - -Show what you're currently tracking in Phrequent. - - -=back - -B<todo> I<summary> [I<options>] - Quickly create a task for yourself. - - -=over - -=item I<--browse> - -=back - - -=over - -After creating the task, open it in a web browser. - -=back - - -=over - -=item I<--cc> I<cc>, I<-C> I<cc> - -=back - - -=over - -Other users to CC on the new task. - -=back - - -=over - -=item I<--project> I<project> - -=back - - -=over - -Projects to assign to the task. - -=back - - - -B<unit> [I<options>] [I<paths>] - -B<unit> [I<options>] --rev [I<rev>] - -=over - -Supports: git, svn, hg -Run unit tests that cover specified paths. If no paths are specified, -unit tests covering all modified files will be run. - - -=over - -=item I<--coverage> - -=back - - -=over - -Always enable coverage information. - -=back - - -=over - -=item I<--detailed-coverage> - -=back - - -=over - -Show a detailed coverage report on the CLI. Implies --coverage. - -=back - - -=over - -=item I<--engine> I<classname> - -=back - - -=over - -Override configured unit engine for this project. - -=back - - -=over - -=item I<--everything> - -=back - - -=over - -Run every test. - -=back - - -=over - -=item I<--json> - -=back - - -=over - -Report results in JSON format. - -=back - - -=over - -=item I<--no-coverage> - -=back - - -=over - -Always disable coverage information. - -=back - - -=over - -=item I<--output> I<format> - -=back - - -=over - -With 'full', show full pretty report (Default). With 'json', -report results in JSON format. With 'ugly', use uglier (but -more efficient) JSON formatting. With 'none', don't print -results. - -=back - - -=over - -=item I<--rev> I<revision> - -=back - - -=over - -Supports: git, hg -Run unit tests covering changes since a specific revision. - -=back - - -=over - -=item I<--target> I<phid> - -=back - - (PROTOTYPE) Record a copy of the test results on the specified - -=over - -Harbormaster build target. - -=back - - -=over - -=item I<--ugly> - -=back - - -=over - -With --json, use uglier (but more efficient) formatting. - -=back - - -=back - -B<upgrade> - -=over - -Supports: cli -Upgrade arcanist and libphutil to the latest versions. - - -=back - -B<upload> I<file> [I<file> ...] [--json] - -=over - -Supports: filesystems -Upload a file from local disk. - - -=over - -=item I<--json> - -=back - - -=over - -Output upload information in JSON format. - -=back - - -=over - -=item I<--temporary> - -=back - - -=over - -Mark the file as temporary. Temporary files will be deleted -automatically after 24 hours. - -=back - - -=back - -B<version> [I<options>] - -=over - -Supports: cli -Shows the current version of arcanist. - - -=back - -B<which> [options] (svn) - -B<which> [options] [I<commit>] (hg, git) - -=over - -Supports: svn, git, hg -Shows which repository the current working copy corresponds to, -which commits 'arc diff' will select, and which revision is in -the working copy (or which revisions, if more than one matches). - - -=over - -=item I<--any-status> - -=back - - -=over - -Show committed and abandoned revisions. - -=back - - -=over - -=item I<--base> I<rules> - -=back - - -=over - -Supports: git, hg -Additional rules for determining base revision. - -=back - - -=over - -=item I<--head> I<commit> - -=back - - -=over - -Supports: git -Specify the end of the commit range to select. - -=back - - -=over - -=item I<--show-base> - -=back - - -=over - -Supports: git, hg -Print base commit only and exit. - -=back - - -=back - -=head1 OPTION REFERENCE - - - -=over - -=item I<--trace> - -=back - -Debugging command. Shows underlying commands as they are executed, -and full stack traces when exceptions are thrown. - - -=over - -=item I<--no-ansi> - -=back - -Output in plain ASCII text only, without color or style. - - -=over - -=item I<--ansi> - -=back - -Use formatting even in environments which probably don't support it. -Example: arc --ansi unit | less -r - - -=over - -=item I<--load-phutil-library=/path/to/library> - -=back - -Ignore libraries listed in .arcconfig and explicitly load specified -libraries instead. Mostly useful for Arcanist development. - - -=over - -=item I<--conduit-uri> I<uri> - -=back - -Ignore configured Conduit URI and use an explicit one instead. Mostly -useful for Arcanist development. - - -=over - -=item I<--conduit-token> I<token> - -=back - -Ignore configured credentials and use an explicit API token instead. - - -=over - -=item I<--conduit-version> I<version> - -=back - -Ignore software version and claim to be running some other version -instead. Mostly useful for Arcanist development. May cause bad things -to happen. - - -=over - -=item I<--conduit-timeout> I<timeout> - -=back - -Override the default Conduit timeout. Specified in seconds. - - -=over - -=item I<--config> I<key=value> - -=back - -Specify a runtime configuration value. This will take precedence -over static values, and only affect the current arcanist invocation. - - -=over - -=item I<--skip-arcconfig> - -=back - -Skip the working copy configuration file - - -=over - -=item I<--arcrc-file> I<filename> - -=back - -Use provided file instead of ~/.arcrc. diff -Nru phabricator-0~git20200925/debian/changelog phabricator-0~git20220903/debian/changelog --- phabricator-0~git20200925/debian/changelog 2020-09-25 07:59:46.000000000 +0000 +++ phabricator-0~git20220903/debian/changelog 2022-10-07 18:06:13.000000000 +0000 @@ -1,3 +1,39 @@ +phabricator (0~git20220903-2) unstable; urgency=medium + + * Support invocation as "arcanist". Closes: #1020840 + + -- Christoph Biedl <debian.axhn@manchmal.in-ulm.de> Fri, 07 Oct 2022 20:06:13 +0200 + +phabricator (0~git20220903-1) unstable; urgency=medium + + * get-orig-source: Update github URLs to https, make reproducible + * Update to latest commits upstream. Closes: #1003463 + * Revert "Provide the phabrication notification service "aphlict" as + a separate package" + * Install the arc program as arcanist. Closes: #919697 + + -- Christoph Biedl <debian.axhn@manchmal.in-ulm.de> Mon, 05 Sep 2022 20:02:43 +0200 + +phabricator (0~git20200925-3) experimental; urgency=medium + + * Upload to experimental + * phabricator package: + - Install more depencencies + - postinst: Poke PHP and mysql configuration + - Provide the phabrication notification service "aphlict" as a + separate package + + -- Christoph Biedl <debian.axhn@manchmal.in-ulm.de> Mon, 07 Jun 2021 13:58:06 +0200 + +phabricator (0~git20200925-2) experimental; urgency=medium + + * Upload to experimental + * Re-enable phabricator package. Closes: #942529 + * Add phabricator patches from Nicolas Dandrimont, thanks + * Add myself as uploader + + -- Christoph Biedl <debian.axhn@manchmal.in-ulm.de> Tue, 26 Jan 2021 18:28:52 +0100 + phabricator (0~git20200925-1) unstable; urgency=medium * New upstream release diff -Nru phabricator-0~git20200925/debian/control phabricator-0~git20220903/debian/control --- phabricator-0~git20200925/debian/control 2019-02-07 12:59:01.000000000 +0000 +++ phabricator-0~git20220903/debian/control 2022-09-08 16:48:13.000000000 +0000 @@ -3,7 +3,7 @@ Priority: optional Maintainer: Sylvestre Ledru <sylvestre@debian.org> Uploaders: - Richard Sellam <richard.sellam@orvidia.fr> + Christoph Biedl <debian.axhn@manchmal.in-ulm.de>, Build-Depends: debhelper (>= 9), po-debconf Standards-Version: 4.1.4 Homepage: http://phabricator.org/ @@ -13,7 +13,7 @@ Package: libphutil Architecture: all Depends: php-xml, ${misc:Depends} -Recommends: php-cli | php5-cli +Recommends: php-cli Description: Shared library for Arcanist and Phabricator libphutil (pronounced as "lib-futile", like the English word futile) is principally the shared library for Arcanist and Phabricator, @@ -23,7 +23,7 @@ Package: arcanist Architecture: all -Depends: libphutil (= ${source:Version}), php-cli | php5-cli, php-curl | php5-curl, ${misc:Depends}, +Depends: libphutil (= ${source:Version}), php-cli, php-curl, ${misc:Depends}, php-xml Conflicts: arc Suggests: python @@ -34,20 +34,33 @@ # Package: phabricator # Architecture: all -# Depends: arcanist, +# Depends: ${misc:Depends}, +# arcanist, +# ca-certificates, +# crudini, # dbconfig-common (>= 1.8.8), # fonts-font-awesome, +# imagemagick, # jq, -# libapache2-mod-php5 | libapache2-mod-php5filter | php5-fpm | php5, +# libapache2-mod-php | php-fpm, # libjs-d3, # libphutil (= ${source:Version}), -# php5-cli, -# php5-curl, -# php5-mysql | php5-mysqli | php5-mysqlnd, +# php-apcu, +# php-cli, +# php-curl, +# php-gd, +# php-mailparse, +# php-mbstring, +# php-mysql | php-mysqli | php-mysqlnd, +# php-zip, +# php, # po-debconf, +# python3-pygments, +# python3-pkg-resources, # ucf, -# ${misc:Depends} -# Recommends: apache2 (>= 2.2.7) | lighttpd | nginx | httpd, php5-apcu, php5-gd, mariadb-server | default-mysql-server | virtual-mysql-server +# Recommends: +# apache2 (>= 2.2.7) | lighttpd | nginx | httpd, +# mariadb-server | default-mysql-server | virtual-mysql-server, # Suggests: python, npm # Description: Software engineering platform # Phabricator is an open source collection of web applications which make it diff -Nru phabricator-0~git20200925/debian/doc/arcanist.1 phabricator-0~git20220903/debian/doc/arcanist.1 --- phabricator-0~git20200925/debian/doc/arcanist.1 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/doc/arcanist.1 2022-09-08 09:46:51.000000000 +0000 @@ -0,0 +1,2244 @@ +.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{ +. if \nF \{ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "ARC 1" +.TH ARC 1 "2016-10-24" "" "User Commands" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +arc \- arcanist, a code review and revision management utility +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBarc\fR \fIcommand\fR [\fIoptions\fR] [\fIargs\fR] +This help file provides a detailed command reference. +.SH "COMMAND REFERENCE" +.IX Header "COMMAND REFERENCE" +\&\fBalias\fR +.PP +\&\fBalias\fR \fIcommand\fR +.PP +\&\fBalias\fR \fIcommand\fR \fItarget\fR \*(-- [\fIoptions\fR] +.Sp +.RS 4 +Supports: cli +Create an alias from \fIcommand\fR to \fItarget\fR (optionally, with +\&\fIoptions\fR). For example: +.Sp +.Vb 1 +\& arc alias fpatch patch \-\- \-\-force +.Ve +.Sp +\&...will create a new 'arc' command, 'arc fpatch', which invokes +\&'arc patch \-\-force ...' when run. \s-1NOTE:\s0 use \*(L"\-\-\*(R" before specifying +options! +.Sp +If you start an alias with \*(L"!\*(R", the remainder of the alias will be +invoked as a shell command. For example, if you want to implement +\&'arc ls', you can do so like this: +.Sp +.Vb 1 +\& arc alias ls \*(Aq!ls\*(Aq +.Ve +.Sp +You can now run \*(L"arc ls\*(R" and it will behave like \*(L"ls\*(R". Of course, this +example is silly and would make your life worse. +.Sp +You can not overwrite builtins, including 'alias' itself. The builtin +will always execute, even if it was added after your alias. +.Sp +To remove an alias, run: +.Sp +.Vb 1 +\& arc alias fpatch +.Ve +.Sp +Without any arguments, 'arc alias' will list aliases. +.RE +.PP +\&\fBamend\fR [\-\-revision \fIrevision_id\fR] [\-\-show] +.Sp +.RS 4 +Supports: git, hg +Amend the working copy, synchronizing the local commit message from +Differential. +.Sp +Supported in Mercurial 2.2 and newer. +.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 +.IX Item "--revision revision_id" +.RE +.RS 4 +.Sp +.RS 4 +Use the message from a specific revision. If you do not specify +a revision, arc will guess which revision is in the working +copy. +.RE +.RE +.RS 4 +.IP "\fI\-\-show\fR" 4 +.IX Item "--show" +.RE +.RS 4 +.Sp +.RS 4 +Show the amended commit message, without modifying the working +copy. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBanoid\fR +.Sp +.RS 4 +There's only one way to find out... +.RE +.PP +\&\fBbackout\fR +.Sp +.RS 4 +Reverts/backouts on a previous commit. Supports: git, hg +.Sp +.RS 4 +Command is used like this: arc backout <commithash> | <diff revision> +Entering a differential revision will only work if there is only one commit +associated with the revision. This requires your working copy is up to date +and that the commit exists in the working copy. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBbookmark\fR [\fIoptions\fR] +.PP +\&\fBbookmark\fR \fIname\fR [\fIstart\fR] +.Sp +.RS 4 +Supports: hg +Alias for arc feature. +.IP "\fI\-\-by\-status\fR" 4 +.IX Item "--by-status" +.RE +.RS 4 +.Sp +.RS 4 +Sort branches by status instead of time. +.RE +.RE +.RS 4 +.IP "\fI\-\-output\fR \fIformat\fR" 4 +.IX Item "--output format" +.RE +.RS 4 +.Sp +.RS 4 +With 'json', show features in machine-readable \s-1JSON\s0 format. +.RE +.RE +.RS 4 +.IP "\fI\-\-view\-all\fR" 4 +.IX Item "--view-all" +.RE +.RS 4 +.Sp +.RS 4 +Include closed and abandoned revisions. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBbranch\fR [\fIoptions\fR] +.PP +\&\fBbranch\fR \fIname\fR [\fIstart\fR] +.Sp +.RS 4 +Supports: git +Alias for arc feature. +.IP "\fI\-\-by\-status\fR" 4 +.IX Item "--by-status" +.RE +.RS 4 +.Sp +.RS 4 +Sort branches by status instead of time. +.RE +.RE +.RS 4 +.IP "\fI\-\-output\fR \fIformat\fR" 4 +.IX Item "--output format" +.RE +.RS 4 +.Sp +.RS 4 +With 'json', show features in machine-readable \s-1JSON\s0 format. +.RE +.RE +.RS 4 +.IP "\fI\-\-view\-all\fR" 4 +.IX Item "--view-all" +.RE +.RS 4 +.Sp +.RS 4 +Include closed and abandoned revisions. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBbrowse\fR [\fIoptions\fR] \fIpath\fR ... +.PP +\&\fBbrowse\fR [\fIoptions\fR] \fIobject\fR ... +.Sp +.RS 4 +Supports: git, hg, svn +Open a file or object (like a task or revision) in your web browser. +.Sp +.Vb 3 +\& $ arc browse README # Open a file in Diffusion. +\& $ arc browse T123 # View a task. +\& $ arc browse HEAD # View a symbolic commit. +.Ve +.Sp +Set the 'browser' value using 'arc set\-config' to select a browser. If +no browser is set, the command will try to guess which browser to use. +.IP "\fI\-\-branch\fR \fIbranch_name\fR" 4 +.IX Item "--branch branch_name" +.RE +.RS 4 +.Sp +.RS 4 +Default branch name to view on server. Defaults to \*(L"master\*(R". +.RE +.RE +.RS 4 +.IP "\fI\-\-force\fR" 4 +.IX Item "--force" +.RE +.RS 4 +.Sp +.RS 4 +Open arguments as paths, even if they do not exist in the +working copy. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBcall-conduit\fR \fImethod\fR +.Sp +.RS 4 +Supports: http, https +Allows you to make a raw Conduit method call: +.Sp +.Vb 3 +\& \- Run this command from a working directory. +\& \- Call parameters are REQUIRED and read as a JSON blob from stdin. +\& \- Results are written to stdout as a JSON blob. +.Ve +.Sp +This workflow is primarily useful for writing scripts which integrate +with Phabricator. Examples: +.Sp +.Vb 2 +\& $ echo \*(Aq{}\*(Aq | arc call\-conduit conduit.ping +\& $ echo \*(Aq{"phid":"PHID\-FILE\-xxxx"}\*(Aq | arc call\-conduit file.download +.Ve +.RE +.PP +\&\fBclose\fR \fItask_id\fR [\fIoptions\fR] + Close a task or otherwise update its status. +.IP "\fI\-\-list\-statuses\fR" 4 +.IX Item "--list-statuses" +.Sp +.RS 4 +Show available status options and exit. +.RE +.IP "\fI\-\-message\fR \fIcomment\fR, \fI\-m\fR \fIcomment\fR" 4 +.IX Item "--message comment, -m comment" +.Sp +.RS 4 +Provide a comment with your status change. +.RE +.IP "\fI\-\-status\fR \fIstatus\fR, \fI\-s\fR \fIstatus\fR" 4 +.IX Item "--status status, -s status" +.Sp +.RS 4 +Specify a new status. Valid status options can be seen with the +`list\-statuses` argument. +.RE +.PP +\&\fBclose-revision\fR [\fIoptions\fR] \fIrevision\fR +.Sp +.RS 4 +Supports: git, hg, svn +Close a revision which has been committed (svn) or pushed (git, hg). +You should not normally need to do this: arc commit (svn), arc amend +(git, hg), arc land (git, hg), or repository tracking on the master +remote repository should do it for you. However, if these mechanisms +have failed for some reason you can use this command to manually +change a revision status from \*(L"Accepted\*(R" to \*(L"Closed\*(R". +.IP "\fI\-\-finalize\fR" 4 +.IX Item "--finalize" +.RE +.RS 4 +.Sp +.RS 4 +Close only if the repository is untracked and the revision is +accepted. Continue even if the close can't happen. This is a +soft version of '' used by other workflows. +.RE +.RE +.RS 4 +.IP "\fI\-\-quiet\fR" 4 +.IX Item "--quiet" +.RE +.RS 4 +.Sp +.RS 4 +Do not print a success message. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBcommit\fR [\-\-revision \fIrevision_id\fR] [\-\-show] +.Sp +.RS 4 +Supports: svn +Commit a revision which has been accepted by a reviewer. +.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 +.IX Item "--revision revision_id" +.RE +.RS 4 +.Sp +.RS 4 +Commit a specific revision. If you do not specify a revision, +arc will look for committable revisions. +.RE +.RE +.RS 4 +.IP "\fI\-\-show\fR" 4 +.IX Item "--show" +.RE +.RS 4 +.Sp +.RS 4 +Show the command which would be issued, but do not actually +commit anything. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBcover\fR [\-\-rev \fIrevision\fR] [\fIpath\fR ...] +.Sp +.RS 4 +Supports: svn, git, hg +Cover your... professional reputation. Show blame for the lines you +changed in your working copy (svn) or since some commit (hg, git). +This will take a minute because blame takes a minute, especially under +\&\s-1SVN.\s0 +.IP "\fI\-\-rev\fR \fIrevision\fR" 4 +.IX Item "--rev revision" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Cover changes since a specific revision. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBdiff\fR [\fIpaths\fR] (svn) +.PP +\&\fBdiff\fR [\fIcommit\fR] (git, hg) +.Sp +.RS 4 +Supports: git, svn, hg +Generate a Differential diff or revision from local changes. +.Sp +Under git and mercurial, you can specify a commit (like \fIHEAD^^^\fR +or \fImaster\fR) and Differential will generate a diff against the +merge base of that commit and your current working directory parent. +.Sp +Under svn, you can choose to include only some of the modified files +in the working copy in the diff by specifying their paths. If you +omit paths, all changes are included in the diff. +.IP "\fI\-\-add\-all\fR, \fI\-a\fR" 4 +.IX Item "--add-all, -a" +.RE +.RS 4 +.Sp +.RS 4 +Automatically add all unstaged and uncommitted files to the +commit. +.RE +.RE +.RS 4 +.IP "\fI\-\-advice\fR" 4 +.IX Item "--advice" +.RE +.RS 4 +.Sp +.RS 4 +Require excuse for lint advice in addition to lint warnings and +errors. +.RE +.RE +.RS 4 +.IP "\fI\-\-allow\-untracked\fR" 4 +.IX Item "--allow-untracked" +.RE +.RS 4 +.Sp +.RS 4 +Skip checks for untracked files in the working copy. +.RE +.RE +.RS 4 +.IP "\fI\-\-amend\-all\fR" 4 +.IX Item "--amend-all" +.RE +.RS 4 +.Sp +.RS 4 +When linting git repositories, amend \s-1HEAD\s0 with all patches +suggested by lint without prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-amend\-autofixes\fR" 4 +.IX Item "--amend-autofixes" +.RE +.RS 4 +.Sp +.RS 4 +When linting git repositories, amend \s-1HEAD\s0 with autofix patches +suggested by lint without prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-apply\-patches\fR" 4 +.IX Item "--apply-patches" +.RE +.RS 4 +.Sp +.RS 4 +Apply patches suggested by lint to the working copy without +prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-base\fR \fIrules\fR" 4 +.IX Item "--base rules" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Additional rules for determining base revision. +.RE +.RE +.RS 4 +.IP "\fI\-\-browse\fR" 4 +.IX Item "--browse" +.RE +.RS 4 +.Sp +.RS 4 +After creating a diff or revision, open it in a web browser. +.RE +.RE +.RS 4 +.IP "\fI\-\-cache\fR \fIbool\fR" 4 +.IX Item "--cache bool" +.RE +.RS 4 +.Sp +.Vb 1 +\& 0 to disable lint cache, 1 to enable (default). +.Ve +.IP "\fI\-\-cc\fR \fIusernames\fR" 4 +.IX Item "--cc usernames" +.RE +.RS 4 +.Sp +.RS 4 +When creating a revision, add CCs. +.RE +.RE +.RS 4 +.IP "\fI\-\-coverage\fR" 4 +.IX Item "--coverage" +.RE +.RS 4 +.Sp +.RS 4 +Always enable coverage information. +.RE +.RE +.RS 4 +.IP "\fI\-\-create\fR" 4 +.IX Item "--create" +.RE +.RS 4 +.Sp +.RS 4 +Always create a new revision. +.RE +.RE +.RS 4 +.IP "\fI\-\-edit\fR" 4 +.IX Item "--edit" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +When updating a revision under git, edit revision information +before updating. +.RE +.RE +.RS 4 +.IP "\fI\-\-encoding\fR \fIencoding\fR" 4 +.IX Item "--encoding encoding" +.RE +.RS 4 +.Sp +.RS 4 +Attempt to convert non \s-1UTF\-8\s0 hunks into specified encoding. +.RE +.RE +.RS 4 +.IP "\fI\-\-excuse\fR \fIexcuse\fR" 4 +.IX Item "--excuse excuse" +.RE +.RS 4 +.Sp +.RS 4 +Provide a prepared in advance excuse for any lints/tests shall +they fail. +.RE +.RE +.RS 4 +.IP "\fI\-\-head\fR \fIcommit\fR" 4 +.IX Item "--head commit" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git +Specify the end of the commit range. This disables many +Arcanist/Phabricator features which depend on having access to +the working copy. +.RE +.RE +.RS 4 +.IP "\fI\-\-ignore\-unsound\-tests\fR" 4 +.IX Item "--ignore-unsound-tests" +.RE +.RS 4 +.Sp +.RS 4 +Ignore unsound test failures without prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-json\fR" 4 +.IX Item "--json" +.RE +.RS 4 +.Sp +.RS 4 +Emit machine-readable \s-1JSON. EXPERIMENTAL\s0! Probably does not +work! +.RE +.RE +.RS 4 +.IP "\fI\-\-less\-context\fR" 4 +.IX Item "--less-context" +.RE +.RS 4 +.Sp +.RS 4 +Normally, files are diffed with full context: the entire file +is sent to Differential so reviewers can 'show more' and see +it. If you are making changes to very large files with tens of +thousands of lines, this may not work well. With this flag, a +diff will be created that has only a few lines of context. +.RE +.RE +.RS 4 +.IP "\fI\-\-lintall\fR" 4 +.IX Item "--lintall" +.RE +.RS 4 +.Sp +.RS 4 +Raise all lint warnings, not just those on lines you changed. +.RE +.RE +.RS 4 +.IP "\fI\-\-message\fR \fImessage\fR, \fI\-m\fR \fImessage\fR" 4 +.IX Item "--message message, -m message" +.RE +.RS 4 +.Sp +.RS 4 +When updating a revision, use the specified message instead of +prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-message\-file\fR \fIfile\fR, \fI\-F\fR \fIfile\fR" 4 +.IX Item "--message-file file, -F file" +.RE +.RS 4 +.Sp +.RS 4 +When creating a revision, read revision information from this +file. +.RE +.RE +.RS 4 +.IP "\fI\-\-never\-apply\-patches\fR" 4 +.IX Item "--never-apply-patches" +.RE +.RS 4 +.Sp +.RS 4 +Never apply patches suggested by lint. +.RE +.RE +.RS 4 +.IP "\fI\-\-no\-amend\fR" 4 +.IX Item "--no-amend" +.RE +.RS 4 +.Sp +.RS 4 +Never amend commits in the working copy with lint patches. +.RE +.RE +.RS 4 +.IP "\fI\-\-no\-coverage\fR" 4 +.IX Item "--no-coverage" +.RE +.RS 4 +.Sp +.RS 4 +Always disable coverage information. +.RE +.RE +.RS 4 +.IP "\fI\-\-no\-diff\fR" 4 +.IX Item "--no-diff" +.RE +.RS 4 +.Sp +.RS 4 +Only run lint and unit tests. Intended for internal use. +.RE +.RE +.RS 4 +.IP "\fI\-\-nolint\fR" 4 +.IX Item "--nolint" +.RE +.RS 4 +.Sp +.RS 4 +Do not run lint. +.RE +.RE +.RS 4 +.IP "\fI\-\-nounit\fR" 4 +.IX Item "--nounit" +.RE +.RS 4 +.Sp +.RS 4 +Do not run unit tests. +.RE +.RE +.RS 4 +.IP "\fI\-\-only\fR" 4 +.IX Item "--only" +.RE +.RS 4 +.Sp +.RS 4 +Only generate a diff, without running lint, unit tests, or +other auxiliary steps. See also \-\-preview. +.RE +.RE +.RS 4 +.IP "\fI\-\-only\-new\fR \fIbool\fR" 4 +.IX Item "--only-new bool" +.RE +.RS 4 +.Sp +.RS 4 +Display only lint messages not present in the original code. +.RE +.RE +.RS 4 +.IP "\fI\-\-plan\-changes\fR" 4 +.IX Item "--plan-changes" +.RE +.RS 4 +.Sp +.RS 4 +Create or update a revision without requesting a code review. +.RE +.RE +.RS 4 +.IP "\fI\-\-preview\fR" 4 +.IX Item "--preview" +.RE +.RS 4 +.Sp +.RS 4 +Instead of creating or updating a revision, only create a diff, +which you may later attach to a revision. This still runs lint +unit tests. See also \-\-only. +.RE +.RE +.RS 4 +.IP "\fI\-\-raw\fR" 4 +.IX Item "--raw" +.RE +.RS 4 +.Sp +.RS 4 +Read diff from stdin, not from the working copy. This disables +many Arcanist/Phabricator features which depend on having +access to the working copy. +.RE +.RE +.RS 4 +.IP "\fI\-\-raw\-command\fR \fIcommand\fR" 4 +.IX Item "--raw-command command" +.RE +.RS 4 +.Sp +.RS 4 +Generate diff by executing a specified command, not from the +working copy. This disables many Arcanist/Phabricator features +which depend on having access to the working copy. +.RE +.RE +.RS 4 +.IP "\fI\-\-reviewers\fR \fIusernames\fR" 4 +.IX Item "--reviewers usernames" +.RE +.RS 4 +.Sp +.RS 4 +When creating a revision, add reviewers. +.RE +.RE +.RS 4 +.IP "\fI\-\-skip\-binaries\fR" 4 +.IX Item "--skip-binaries" +.RE +.RS 4 +.Sp +.RS 4 +Do not upload binaries (like images). +.RE +.RE +.RS 4 +.IP "\fI\-\-skip\-staging\fR" 4 +.IX Item "--skip-staging" +.RE +.RS 4 +.Sp +.RS 4 +Do not copy changes to the staging area. +.RE +.RE +.RS 4 +.IP "\fI\-\-uncommitted\fR" 4 +.IX Item "--uncommitted" +.RE +.RS 4 +.Sp +.RS 4 +Supports: hg +Suppress warning about uncommitted changes. +.RE +.RE +.RS 4 +.IP "\fI\-\-update\fR \fIrevision_id\fR" 4 +.IX Item "--update revision_id" +.RE +.RS 4 +.Sp +.RS 4 +Always update a specific revision. +.RE +.RE +.RS 4 +.IP "\fI\-\-use\-commit\-message\fR \fIcommit\fR, \fI\-C\fR \fIcommit\fR" 4 +.IX Item "--use-commit-message commit, -C commit" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git +Read revision information from a specific commit. +.RE +.RE +.RS 4 +.IP "\fI\-\-verbatim\fR" 4 +.IX Item "--verbatim" +.RE +.RS 4 +.Sp +.RS 4 +Supports: hg, git +When creating a revision, try to use the working copy commit +message verbatim, without prompting to edit it. When updating a +revision, update some fields from the local commit message. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBdownload\fR \fIfile\fR [\-\-as \fIname\fR] [\-\-show] +.Sp +.RS 4 +Supports: filesystems +Download a file to local disk, e.g.: +.Sp +.Vb 1 +\& $ arc download F33 # Download file \*(AqF33\*(Aq +.Ve +.IP "\fI\-\-as\fR \fIname\fR" 4 +.IX Item "--as name" +.RE +.RS 4 +.Sp +.RS 4 +Save the file with a specific name rather than the default. +.RE +.RE +.RS 4 +.IP "\fI\-\-show\fR" 4 +.IX Item "--show" +.RE +.RS 4 +.Sp +.RS 4 +Write file to stdout instead of to disk. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBexport\fR [\fIpaths\fR] \fIformat\fR (svn) +.PP +\&\fBexport\fR [\fIcommit_range\fR] \fIformat\fR (git, hg) +.PP +\&\fBexport\fR \fI\-\-revision\fR \fIrevision_id\fR \fIformat\fR +.PP +\&\fBexport\fR \fI\-\-diff\fR \fIdiff_id\fR \fIformat\fR +.Sp +.RS 4 +Supports: svn, git, hg +Export the local changeset (or a Differential changeset) to a file, +in some \fIformat\fR: git diff (\fI\-\-git\fR), unified diff +(\fI\-\-unified\fR), or arc bundle (\fI\-\-arcbundle\fR \fIpath\fR) format. +.IP "\fI\-\-arcbundle\fR \fIfile\fR" 4 +.IX Item "--arcbundle file" +.RE +.RS 4 +.Sp +.RS 4 +Export change as an arc bundle. This format can represent all +changes. These bundles can be applied with 'arc patch'. +.RE +.RE +.RS 4 +.IP "\fI\-\-diff\fR \fIdiff_id\fR" 4 +.IX Item "--diff diff_id" +.RE +.RS 4 +.Sp +.RS 4 +Instead of exporting changes from the working copy, export them +from a Differential diff. +.RE +.RE +.RS 4 +.IP "\fI\-\-encoding\fR \fIencoding\fR" 4 +.IX Item "--encoding encoding" +.RE +.RS 4 +.Sp +.RS 4 +Attempt to convert non \s-1UTF\-8\s0 patch into specified encoding. +.RE +.RE +.RS 4 +.IP "\fI\-\-git\fR" 4 +.IX Item "--git" +.RE +.RS 4 +.Sp +.RS 4 +Export change as a git patch. This format is more complete than +unified, but less complete than arc bundles. These patches can +be applied with 'git apply' or 'arc patch'. +.RE +.RE +.RS 4 +.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 +.IX Item "--revision revision_id" +.RE +.RS 4 +.Sp +.RS 4 +Instead of exporting changes from the working copy, export them +from a Differential revision. +.RE +.RE +.RS 4 +.IP "\fI\-\-unified\fR" 4 +.IX Item "--unified" +.RE +.RS 4 +.Sp +.RS 4 +Export change as a unified patch. This format is less complete +than git patches or arc bundles. These patches can be applied +with 'patch' or 'arc patch'. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBfeature\fR [\fIoptions\fR] +.PP +\&\fBfeature\fR \fIname\fR [\fIstart\fR] +.Sp +.RS 4 +Supports: git, hg +A wrapper on 'git branch' or 'hg bookmark'. +.Sp +Without \fIname\fR, it lists the available branches and their revision +status. +.Sp +With \fIname\fR, it creates or checks out a branch. If the branch +\&\fIname\fR doesn't exist and is in format D123 then the branch of +revision D123 is checked out. Use \fIstart\fR to specify where the new +branch will start. Use 'arc.feature.start.default' to set the default +feature start location. +.IP "\fI\-\-by\-status\fR" 4 +.IX Item "--by-status" +.RE +.RS 4 +.Sp +.RS 4 +Sort branches by status instead of time. +.RE +.RE +.RS 4 +.IP "\fI\-\-output\fR \fIformat\fR" 4 +.IX Item "--output format" +.RE +.RS 4 +.Sp +.RS 4 +With 'json', show features in machine-readable \s-1JSON\s0 format. +.RE +.RE +.RS 4 +.IP "\fI\-\-view\-all\fR" 4 +.IX Item "--view-all" +.RE +.RS 4 +.Sp +.RS 4 +Include closed and abandoned revisions. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBflag\fR [\fIobject\fR ...] +.PP +\&\fBflag\fR \fIobject\fR \-\-clear +.PP +\&\fBflag\fR \fIobject\fR [\-\-edit] [\-\-color \fIcolor\fR] [\-\-note \fInote\fR] +.Sp +.RS 4 +In the first form, list objects you've flagged. You can provide the +names of one or more objects (Maniphest tasks T#, Differential +revisions D#, Diffusion references rXXX???, or PHIDs \s-1PHID\-XXX\-\s0???) +to print only flags for those objects. +.Sp +In the second form, clear an existing flag on one object. +.Sp +In the third form, create or update a flag on one object. Color +defaults to blue and note to empty, but if you omit both you must +pass \-\-edit. +.IP "\fI\-\-clear\fR" 4 +.IX Item "--clear" +.RE +.RS 4 +.Sp +.RS 4 +Delete the flag on an object. +.RE +.RE +.RS 4 +.IP "\fI\-\-color\fR \fIcolor\fR" 4 +.IX Item "--color color" +.RE +.RS 4 +.Sp +.RS 4 +Set the color of a flag. +.RE +.RE +.RS 4 +.IP "\fI\-\-edit\fR" 4 +.IX Item "--edit" +.RE +.RS 4 +.Sp +.RS 4 +Edit the flag on an object. +.RE +.RE +.RS 4 +.IP "\fI\-\-note\fR \fInote\fR" 4 +.IX Item "--note note" +.RE +.RS 4 +.Sp +.RS 4 +Set the note on a flag. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBget-config\fR [\fIoptions\fR] \*(-- [\fIname\fR ...] +.Sp +.RS 4 +Supports: cli +Reads an arc configuration option. With no argument, reads all +options. +.Sp +With \fI\-\-verbose\fR, shows detailed information about one or more +options. +.IP "\fI\-\-verbose\fR" 4 +.IX Item "--verbose" +.RE +.RS 4 +.Sp +.RS 4 +Show detailed information about options. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBhelp\fR [\fIcommand\fR] +.PP +\&\fBhelp\fR \-\-full +.Sp +.RS 4 +Supports: english +Shows this help. With \fIcommand\fR, shows help about a specific +command. +.IP "\fI\-\-full\fR" 4 +.IX Item "--full" +.RE +.RS 4 +.Sp +.RS 4 +Print detailed information about each command. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBinstall-certificate\fR [uri] +.Sp +.RS 4 +Supports: http, https +Installs Conduit credentials into your ~/.arcrc for the given install +of Phabricator. You need to do this before you can use 'arc', as it +enables 'arc' to link your command-line activity with your account on +the web. Run this command from within a project directory to install +that project's certificate, or specify an explicit \s-1URI \s0(like +\&\*(L"https://phabricator.example.com/\*(R"). +.RE +.PP +\&\fBland\fR [\fIoptions\fR] [\fIref\fR] +.Sp +.RS 4 +Supports: git, hg +.Sp +Publish an accepted revision after review. This command is the last +step in the standard Differential pre-publish code review workflow. +.Sp +This command merges and pushes changes associated with an accepted +revision that are currently sitting in \fIref\fR, which is usually the +name of a local branch. Without \fIref\fR, the current working copy +state will be used. +.Sp +Under Git: branches, tags, and arbitrary commits (detached HEADs) +may be landed. +.Sp +Under Mercurial: branches and bookmarks may be landed, but only +onto a target of the same type. See T3855. +.Sp +The workflow selects a target branch to land onto and a remote where +the change will be pushed to. +.Sp +A target branch is selected by examining these sources in order: +.Sp +.Vb 6 +\& \- the B<\-\-onto> flag; +\& \- the upstream of the current branch, recursively (Git only); +\& \- the I<arc.land.onto.default> configuration setting; +\& \- or by falling back to a standard default: +\& \- "master" in Git; +\& \- "default" in Mercurial. +.Ve +.Sp +A remote is selected by examining these sources in order: +.Sp +.Vb 5 +\& \- the B<\-\-remote> flag; +\& \- the upstream of the current branch, recursively (Git only); +\& \- or by falling back to a standard default: +\& \- "origin" in Git; +\& \- the default remote in Mercurial. +.Ve +.Sp +After selecting a target branch and a remote, the commits which will +be landed are printed. +.Sp +With \fB\-\-preview\fR, execution stops here, before the change is +merged. +.Sp +The change is merged with the changes in the target branch, +following these rules: +.Sp +In repositories with mutable history or with \fB\-\-squash\fR, this will +perform a squash merge (the entire branch will be represented as one +commit after the merge). +.Sp +In repositories with immutable history or with \fB\-\-merge\fR, this will +perform a strict merge (a merge commit will always be created, and +local commits will be preserved). +.Sp +The resulting commit will be given an up-to-date commit message +describing the final state of the revision in Differential. +.Sp +In Git, the merge occurs in a detached \s-1HEAD.\s0 The local branch +reference (if one exists) is not updated yet. +.Sp +With \fB\-\-hold\fR, execution stops here, before the change is pushed. +.Sp +The change is pushed into the remote. +.Sp +Consulting mystical sources of power, the workflow makes a guess +about what state you wanted to end up in after the process finishes +and the working copy is put into that state. +.Sp +The branch which was landed is deleted, unless the \fB\-\-keep\-branch\fR +flag was passed or the landing branch is the same as the target +branch. +.IP "\fI\-\-delete\-remote\fR" 4 +.IX Item "--delete-remote" +.RE +.RS 4 +.Sp +.RS 4 +Delete the feature branch in the remote after landing it. +.RE +.RE +.RS 4 +.IP "\fI\-\-hold\fR" 4 +.IX Item "--hold" +.RE +.RS 4 +.Sp +.RS 4 +Prepare the change to be pushed, but do not actually push it. +.RE +.RE +.RS 4 +.IP "\fI\-\-keep\-branch\fR" 4 +.IX Item "--keep-branch" +.RE +.RS 4 +.Sp +.RS 4 +Keep the feature branch after pushing changes to the remote (by +default, it is deleted). +.RE +.RE +.RS 4 +.IP "\fI\-\-merge\fR" 4 +.IX Item "--merge" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git +Perform a \-\-no\-ff merge, not a \-\-squash merge. If the project +is marked as having an immutable history, this is the default +behavior. +.RE +.RE +.RS 4 +.IP "\fI\-\-onto\fR \fImaster\fR" 4 +.IX Item "--onto master" +.RE +.RS 4 +.Sp +.RS 4 +Land feature branch onto a branch other than the default +('master' in git, 'default' in hg). You can change the default +by setting 'arc.land.onto.default' with `arc set\-config` or for +the entire project in .arcconfig. +.RE +.RE +.RS 4 +.IP "\fI\-\-preview\fR" 4 +.IX Item "--preview" +.RE +.RS 4 +.Sp +.RS 4 +Prints the commits that would be landed. Does not actually +modify or land the commits. +.RE +.RE +.RS 4 +.IP "\fI\-\-remote\fR \fIorigin\fR" 4 +.IX Item "--remote origin" +.RE +.RS 4 +.Sp +.RS 4 +Push to a remote other than the default ('origin' in git). +.RE +.RE +.RS 4 +.IP "\fI\-\-revision\fR \fIid\fR" 4 +.IX Item "--revision id" +.RE +.RS 4 +.Sp +.RS 4 +Use the message from a specific revision, rather than inferring +the revision based on branch content. +.RE +.RE +.RS 4 +.IP "\fI\-\-squash\fR" 4 +.IX Item "--squash" +.RE +.RS 4 +.Sp +.RS 4 +Perform a \-\-squash merge, not a \-\-no\-ff merge. If the project +is marked as having a mutable history, this is the default +behavior. +.RE +.RE +.RS 4 +.IP "\fI\-\-update\-with\-merge\fR" 4 +.IX Item "--update-with-merge" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git +When updating the feature branch, use merge instead of rebase. +This is the default behavior. Setting arc.land.update.default +to 'merge' can also be used to make this the default. +.RE +.RE +.RS 4 +.IP "\fI\-\-update\-with\-rebase\fR" 4 +.IX Item "--update-with-rebase" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git +When updating the feature branch, use rebase instead of merge. +This might make things work better in some cases. Set +arc.land.update.default to 'rebase' to make this the default. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBliberate\fR [\fIpath\fR] +.Sp +.RS 4 +Supports: libphutil +Create or update a libphutil library, generating required metadata +files like \fIinit\fR.php. +.IP "\fI\-\-all\fR" 4 +.IX Item "--all" +.RE +.RS 4 +.Sp +.RS 4 +Drop the module cache before liberating. This will completely +reanalyze the entire library. Thorough, but slow! +.RE +.RE +.RS 4 +.IP "\fI\-\-force\-update\fR" 4 +.IX Item "--force-update" +.RE +.RS 4 +.Sp +.RS 4 +Force the library map to be updated, even in the presence of +lint errors. +.RE +.RE +.RS 4 +.IP "\fI\-\-library\-name\fR \fIname\fR" 4 +.IX Item "--library-name name" +.RE +.RS 4 +.Sp +.RS 4 +Use a flag for library name rather than awaiting user input. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBlint\fR [\fIoptions\fR] [\fIpaths\fR] +.PP +\&\fBlint\fR [\fIoptions\fR] \-\-rev [\fIrev\fR] +.Sp +.RS 4 +Supports: git, svn, hg +Run static analysis on changes to check for mistakes. If no files +are specified, lint will be run on all files which have been modified. +.IP "\fI\-\-amend\-all\fR" 4 +.IX Item "--amend-all" +.RE +.RS 4 +.Sp +.RS 4 +When linting git repositories, amend \s-1HEAD\s0 with all patches +suggested by lint without prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-amend\-autofixes\fR" 4 +.IX Item "--amend-autofixes" +.RE +.RS 4 +.Sp +.RS 4 +When linting git repositories, amend \s-1HEAD\s0 with autofix patches +suggested by lint without prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-apply\-patches\fR" 4 +.IX Item "--apply-patches" +.RE +.RS 4 +.Sp +.RS 4 +Apply patches suggested by lint to the working copy without +prompting. +.RE +.RE +.RS 4 +.IP "\fI\-\-cache\fR \fIbool\fR" 4 +.IX Item "--cache bool" +.RE +.RS 4 +.Sp +.Vb 3 +\& 0 to disable cache, 1 to enable. The default value is +\& determined by \*(Aqarc.lint.cache\*(Aq in configuration, which defaults +\& to off. See notes in \*(Aqarc.lint.cache\*(Aq. +.Ve +.IP "\fI\-\-engine\fR \fIclassname\fR" 4 +.IX Item "--engine classname" +.RE +.RS 4 +.Sp +.RS 4 +Override configured lint engine for this project. +.RE +.RE +.RS 4 +.IP "\fI\-\-everything\fR" 4 +.IX Item "--everything" +.RE +.RS 4 +.Sp +.RS 4 +Lint all files in the project. +.RE +.RE +.RS 4 +.IP "\fI\-\-lintall\fR" 4 +.IX Item "--lintall" +.RE +.RS 4 +.Sp +.RS 4 +Show all lint warnings, not just those on changed lines. When +paths are specified, this is the default behavior. +.RE +.RE +.RS 4 +.IP "\fI\-\-never\-apply\-patches\fR" 4 +.IX Item "--never-apply-patches" +.RE +.RS 4 +.Sp +.RS 4 +Never apply patches suggested by lint. +.RE +.RE +.RS 4 +.IP "\fI\-\-only\-changed\fR" 4 +.IX Item "--only-changed" +.RE +.RS 4 +.Sp +.RS 4 +Show lint warnings just on changed lines. When no paths are +specified, this is the default. This differs from only-new in +cases where line modifications introduce lint on other +unmodified lines. +.RE +.RE +.RS 4 +.IP "\fI\-\-only\-new\fR \fIbool\fR" 4 +.IX Item "--only-new bool" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Display only messages not present in the original code. +.RE +.RE +.RS 4 +.IP "\fI\-\-outfile\fR \fIpath\fR" 4 +.IX Item "--outfile path" +.RE +.RS 4 +.Sp +.RS 4 +Output the linter results to a file. Defaults to stdout. +.RE +.RE +.RS 4 +.IP "\fI\-\-output\fR \fIformat\fR" 4 +.IX Item "--output format" +.RE +.RS 4 +.Sp +.RS 4 +With 'summary', show lint warnings in a more compact format. +With 'json', show lint warnings in machine-readable \s-1JSON\s0 +format. With 'none', show no lint warnings. With 'compiler', +show lint warnings in suitable for your editor. With 'xml', +show lint warnings in the Checkstyle \s-1XML\s0 format. +.RE +.RE +.RS 4 +.IP "\fI\-\-rev\fR \fIrevision\fR" 4 +.IX Item "--rev revision" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Lint changes since a specific revision. +.RE +.RE +.RS 4 +.IP "\fI\-\-severity\fR \fIstring\fR" 4 +.IX Item "--severity string" +.RE +.RS 4 +.Sp +.RS 4 +Set minimum message severity. One of: 'advice', 'autofix', +\&'warning', 'error', 'disabled'. Defaults to 'advice'. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBlinters\fR [\fIoptions\fR] [\fIname\fR] +.Sp +.RS 4 +Supports: cli +List the available and configured linters, with information about +what they do and which versions are installed. +.Sp +if \fIname\fR is provided, the linter with that name will be displayed. +.IP "\fI\-\-search\fR \fIsearch\fR" 4 +.IX Item "--search search" +.RE +.RS 4 +.Sp +.RS 4 +Search for linters. Search is case-insensitive, and is +performedagainst name and description of each linter. +.RE +.RE +.RS 4 +.IP "\fI\-\-verbose\fR" 4 +.IX Item "--verbose" +.RE +.RS 4 +.Sp +.RS 4 +Show detailed information, including options. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBlist\fR +.Sp +.RS 4 +Supports: git, svn, hg +List your open Differential revisions. +.RE +.PP +\&\fBpaste\fR [\-\-title \fItitle\fR] [\-\-lang \fIlanguage\fR] [\-\-json] +.PP +\&\fBpaste\fR \fIid\fR [\-\-json] +.Sp +.RS 4 +Supports: text +Share and grab text using the Paste application. To create a paste, +use stdin to provide the text: +.Sp +.Vb 1 +\& $ cat list_of_ducks.txt | arc paste +.Ve +.Sp +To retrieve a paste, specify the paste \s-1ID:\s0 +.Sp +.Vb 1 +\& $ arc paste P123 +.Ve +.IP "\fI\-\-json\fR" 4 +.IX Item "--json" +.RE +.RS 4 +.Sp +.RS 4 +Output in \s-1JSON\s0 format. +.RE +.RE +.RS 4 +.IP "\fI\-\-lang\fR \fIlanguage\fR" 4 +.IX Item "--lang language" +.RE +.RS 4 +.Sp +.RS 4 +Language for syntax highlighting. +.RE +.RE +.RS 4 +.IP "\fI\-\-title\fR \fItitle\fR" 4 +.IX Item "--title title" +.RE +.RS 4 +.Sp +.RS 4 +Title for the paste. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBpatch\fR \fID12345\fR +.PP +\&\fBpatch\fR \fI\-\-revision\fR \fIrevision_id\fR +.PP +\&\fBpatch\fR \fI\-\-diff\fR \fIdiff_id\fR +.PP +\&\fBpatch\fR \fI\-\-patch\fR \fIfile\fR +.PP +\&\fBpatch\fR \fI\-\-arcbundle\fR \fIbundlefile\fR +.Sp +.RS 4 +Supports: git, svn, hg +Apply the changes in a Differential revision, patchfile, or arc +bundle to the working copy. +.IP "\fI\-\-arcbundle\fR \fIbundlefile\fR" 4 +.IX Item "--arcbundle bundlefile" +.RE +.RS 4 +.Sp +.RS 4 +Apply changes from an arc bundle generated with 'arc export'. +.RE +.RE +.RS 4 +.IP "\fI\-\-diff\fR \fIdiff_id\fR" 4 +.IX Item "--diff diff_id" +.RE +.RS 4 +.Sp +.RS 4 +Apply changes from a Differential diff. Normally you want to +use \-\-revision to get the most recent changes, but you can +specifically apply an out-of-date diff or a diff which was +never attached to a revision by using this flag. +.RE +.RE +.RS 4 +.IP "\fI\-\-encoding\fR \fIencoding\fR" 4 +.IX Item "--encoding encoding" +.RE +.RS 4 +.Sp +.RS 4 +Attempt to convert non \s-1UTF\-8\s0 patch into specified encoding. +.RE +.RE +.RS 4 +.IP "\fI\-\-force\fR" 4 +.IX Item "--force" +.RE +.RS 4 +.Sp +.RS 4 +Do not run any sanity checks. +.RE +.RE +.RS 4 +.IP "\fI\-\-nobranch\fR" 4 +.IX Item "--nobranch" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Normally, a new branch (git) or bookmark (hg) is created and +then the patch is applied and committed in the new +branch/bookmark. This flag cherry-picks the resultant commit +onto the original branch and deletes the temporary branch. +.RE +.RE +.RS 4 +.IP "\fI\-\-nocommit\fR" 4 +.IX Item "--nocommit" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Normally under git/hg, if the patch is successful, the changes +are committed to the working copy. This flag prevents the +commit. +.RE +.RE +.RS 4 +.IP "\fI\-\-patch\fR \fIpatchfile\fR" 4 +.IX Item "--patch patchfile" +.RE +.RS 4 +.Sp +.RS 4 +Apply changes from a git patchfile or unified patchfile. +.RE +.RE +.RS 4 +.IP "\fI\-\-revision\fR \fIrevision_id\fR" 4 +.IX Item "--revision revision_id" +.RE +.RS 4 +.Sp +.RS 4 +Apply changes from a Differential revision, using the most +recent diff that has been attached to it. You can run 'arc +patch D12345' as a shorthand. +.RE +.RE +.RS 4 +.IP "\fI\-\-skip\-dependencies\fR" 4 +.IX Item "--skip-dependencies" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Normally, if a patch has dependencies that are not present in +the working copy, arc tries to apply them as well. This flag +prevents such work. +.RE +.RE +.RS 4 +.IP "\fI\-\-update\fR" 4 +.IX Item "--update" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, svn, hg +Update the local working copy before applying the patch. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBrevert\fR +Please use arc backout instead +.PP +\&\fBset-config\fR [\fIoptions\fR] \*(-- \fIname\fR \fIvalue\fR +.Sp +.RS 4 +Supports: cli +Sets an arc configuration option. +.Sp +Options are either user (apply to all arc commands you invoke +from the current user) or local (apply only to the current working +copy). By default, user configuration is written. Use \fI\-\-local\fR +to write local configuration. +.Sp +User values are written to '~/.arcrc' on Linux and Mac \s-1OS X,\s0 and an +undisclosed location on Windows. Local values are written to an arc +directory under either .git, .hg, or .svn as appropriate. +.IP "\fI\-\-local\fR" 4 +.IX Item "--local" +.RE +.RS 4 +.Sp +.RS 4 +Set a local config value instead of a user one. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBshell-complete\fR \fI\-\-current\fR \fIN\fR \*(-- [\fIargv\fR] +.Sp +.RS 4 +Supports: bash, etc. +Implements shell completion. To use shell completion, source the +appropriate script from 'resources/shell/' in your .shellrc. +.IP "\fI\-\-current\fR \fIcursor_position\fR" 4 +.IX Item "--current cursor_position" +.RE +.RS 4 +.Sp +.RS 4 +Current term in the argument list being completed. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBstart\fR \fIobject\fR +.Sp +.RS 4 +Start tracking work in Phrequent. +.RE +.PP +\&\fBstop\fR [\-\-note \fInote\fR] [\fIobjects\fR] +.Sp +.RS 4 +Stop tracking work in Phrequent. +.IP "\fI\-\-note\fR \fInote\fR" 4 +.IX Item "--note note" +.RE +.RS 4 +.Sp +.RS 4 +A note to attach to the tracked time. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBtasks\fR [\fIoptions\fR] + View all assigned tasks. +.IP "\fI\-\-limit\fR \fIn\fR" 4 +.IX Item "--limit n" +.Sp +.RS 4 +Limit the amount of tasks outputted, default is all. +.RE +.IP "\fI\-\-order\fR \fItask_order\fR" 4 +.IX Item "--order task_order" +.Sp +.RS 4 +Arrange tasks based on priority, created, or modified, default +is priority. +.RE +.IP "\fI\-\-owner\fR \fIusername\fR" 4 +.IX Item "--owner username" +.Sp +.RS 4 +Only show tasks assigned to the given username, also accepts +\&\f(CW@all\fR to show all, default is you. +.RE +.IP "\fI\-\-status\fR \fItask_status\fR" 4 +.IX Item "--status task_status" +.Sp +.RS 4 +Show tasks that are open or closed, default is open. +.RE +.IP "\fI\-\-unassigned\fR" 4 +.IX Item "--unassigned" +.Sp +.RS 4 +Only show tasks that are not assigned (upforgrabs). +.RE +.PP +\&\fBtime\fR +.Sp +.RS 4 +Show what you're currently tracking in Phrequent. +.RE +.PP +\&\fBtodo\fR \fIsummary\fR [\fIoptions\fR] + Quickly create a task for yourself. +.IP "\fI\-\-browse\fR" 4 +.IX Item "--browse" +.Sp +.RS 4 +After creating the task, open it in a web browser. +.RE +.IP "\fI\-\-cc\fR \fIcc\fR, \fI\-C\fR \fIcc\fR" 4 +.IX Item "--cc cc, -C cc" +.Sp +.RS 4 +Other users to \s-1CC\s0 on the new task. +.RE +.IP "\fI\-\-project\fR \fIproject\fR" 4 +.IX Item "--project project" +.Sp +.RS 4 +Projects to assign to the task. +.RE +.PP +\&\fBunit\fR [\fIoptions\fR] [\fIpaths\fR] +.PP +\&\fBunit\fR [\fIoptions\fR] \-\-rev [\fIrev\fR] +.Sp +.RS 4 +Supports: git, svn, hg +Run unit tests that cover specified paths. If no paths are specified, +unit tests covering all modified files will be run. +.IP "\fI\-\-coverage\fR" 4 +.IX Item "--coverage" +.RE +.RS 4 +.Sp +.RS 4 +Always enable coverage information. +.RE +.RE +.RS 4 +.IP "\fI\-\-detailed\-coverage\fR" 4 +.IX Item "--detailed-coverage" +.RE +.RS 4 +.Sp +.RS 4 +Show a detailed coverage report on the \s-1CLI.\s0 Implies \-\-coverage. +.RE +.RE +.RS 4 +.IP "\fI\-\-engine\fR \fIclassname\fR" 4 +.IX Item "--engine classname" +.RE +.RS 4 +.Sp +.RS 4 +Override configured unit engine for this project. +.RE +.RE +.RS 4 +.IP "\fI\-\-everything\fR" 4 +.IX Item "--everything" +.RE +.RS 4 +.Sp +.RS 4 +Run every test. +.RE +.RE +.RS 4 +.IP "\fI\-\-json\fR" 4 +.IX Item "--json" +.RE +.RS 4 +.Sp +.RS 4 +Report results in \s-1JSON\s0 format. +.RE +.RE +.RS 4 +.IP "\fI\-\-no\-coverage\fR" 4 +.IX Item "--no-coverage" +.RE +.RS 4 +.Sp +.RS 4 +Always disable coverage information. +.RE +.RE +.RS 4 +.IP "\fI\-\-output\fR \fIformat\fR" 4 +.IX Item "--output format" +.RE +.RS 4 +.Sp +.RS 4 +With 'full', show full pretty report (Default). With 'json', +report results in \s-1JSON\s0 format. With 'ugly', use uglier (but +more efficient) \s-1JSON\s0 formatting. With 'none', don't print +results. +.RE +.RE +.RS 4 +.IP "\fI\-\-rev\fR \fIrevision\fR" 4 +.IX Item "--rev revision" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Run unit tests covering changes since a specific revision. +.RE +.RE +.RS 4 +.IP "\fI\-\-target\fR \fIphid\fR" 4 +.IX Item "--target phid" +.RE +.RS 4 +.Sp +.Vb 1 +\& (PROTOTYPE) Record a copy of the test results on the specified +.Ve +.Sp +.RS 4 +Harbormaster build target. +.RE +.RE +.RS 4 +.IP "\fI\-\-ugly\fR" 4 +.IX Item "--ugly" +.RE +.RS 4 +.Sp +.RS 4 +With \-\-json, use uglier (but more efficient) formatting. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBupgrade\fR +.Sp +.RS 4 +Supports: cli +Upgrade arcanist and libphutil to the latest versions. +.RE +.PP +\&\fBupload\fR \fIfile\fR [\fIfile\fR ...] [\-\-json] +.Sp +.RS 4 +Supports: filesystems +Upload a file from local disk. +.IP "\fI\-\-json\fR" 4 +.IX Item "--json" +.RE +.RS 4 +.Sp +.RS 4 +Output upload information in \s-1JSON\s0 format. +.RE +.RE +.RS 4 +.IP "\fI\-\-temporary\fR" 4 +.IX Item "--temporary" +.RE +.RS 4 +.Sp +.RS 4 +Mark the file as temporary. Temporary files will be deleted +automatically after 24 hours. +.RE +.RE +.RS 4 +.RE +.PP +\&\fBversion\fR [\fIoptions\fR] +.Sp +.RS 4 +Supports: cli +Shows the current version of arcanist. +.RE +.PP +\&\fBwhich\fR [options] (svn) +.PP +\&\fBwhich\fR [options] [\fIcommit\fR] (hg, git) +.Sp +.RS 4 +Supports: svn, git, hg +Shows which repository the current working copy corresponds to, +which commits 'arc diff' will select, and which revision is in +the working copy (or which revisions, if more than one matches). +.IP "\fI\-\-any\-status\fR" 4 +.IX Item "--any-status" +.RE +.RS 4 +.Sp +.RS 4 +Show committed and abandoned revisions. +.RE +.RE +.RS 4 +.IP "\fI\-\-base\fR \fIrules\fR" 4 +.IX Item "--base rules" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Additional rules for determining base revision. +.RE +.RE +.RS 4 +.IP "\fI\-\-head\fR \fIcommit\fR" 4 +.IX Item "--head commit" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git +Specify the end of the commit range to select. +.RE +.RE +.RS 4 +.IP "\fI\-\-show\-base\fR" 4 +.IX Item "--show-base" +.RE +.RS 4 +.Sp +.RS 4 +Supports: git, hg +Print base commit only and exit. +.RE +.RE +.RS 4 +.RE +.SH "OPTION REFERENCE" +.IX Header "OPTION REFERENCE" +.IP "\fI\-\-trace\fR" 4 +.IX Item "--trace" +.PP +Debugging command. Shows underlying commands as they are executed, +and full stack traces when exceptions are thrown. +.IP "\fI\-\-no\-ansi\fR" 4 +.IX Item "--no-ansi" +.PP +Output in plain \s-1ASCII\s0 text only, without color or style. +.IP "\fI\-\-ansi\fR" 4 +.IX Item "--ansi" +.PP +Use formatting even in environments which probably don't support it. +Example: arc \-\-ansi unit | less \-r +.IP "\fI\-\-load\-phutil\-library=/path/to/library\fR" 4 +.IX Item "--load-phutil-library=/path/to/library" +.PP +Ignore libraries listed in .arcconfig and explicitly load specified +libraries instead. Mostly useful for Arcanist development. +.IP "\fI\-\-conduit\-uri\fR \fIuri\fR" 4 +.IX Item "--conduit-uri uri" +.PP +Ignore configured Conduit \s-1URI\s0 and use an explicit one instead. Mostly +useful for Arcanist development. +.IP "\fI\-\-conduit\-token\fR \fItoken\fR" 4 +.IX Item "--conduit-token token" +.PP +Ignore configured credentials and use an explicit \s-1API\s0 token instead. +.IP "\fI\-\-conduit\-version\fR \fIversion\fR" 4 +.IX Item "--conduit-version version" +.PP +Ignore software version and claim to be running some other version +instead. Mostly useful for Arcanist development. May cause bad things +to happen. +.IP "\fI\-\-conduit\-timeout\fR \fItimeout\fR" 4 +.IX Item "--conduit-timeout timeout" +.PP +Override the default Conduit timeout. Specified in seconds. +.IP "\fI\-\-config\fR \fIkey=value\fR" 4 +.IX Item "--config key=value" +.PP +Specify a runtime configuration value. This will take precedence +over static values, and only affect the current arcanist invocation. +.IP "\fI\-\-skip\-arcconfig\fR" 4 +.IX Item "--skip-arcconfig" +.PP +Skip the working copy configuration file +.IP "\fI\-\-arcrc\-file\fR \fIfilename\fR" 4 +.IX Item "--arcrc-file filename" +.PP +Use provided file instead of ~/.arcrc. diff -Nru phabricator-0~git20200925/debian/doc/arcanist.cat1 phabricator-0~git20220903/debian/doc/arcanist.cat1 --- phabricator-0~git20200925/debian/doc/arcanist.cat1 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/doc/arcanist.cat1 2022-09-08 09:46:51.000000000 +0000 @@ -0,0 +1,1002 @@ +NAME + arc - arcanist, a code review and revision management utility + +SYNOPSIS + arc command [options] [args] + This help file provides a detailed command reference. + +COMMAND REFERENCE + + alias + alias command + alias command target -- [options] + Supports: cli + Create an alias from command to target (optionally, with + options). For example: + + arc alias fpatch patch -- --force + + ...will create a new 'arc' command, 'arc fpatch', which invokes + 'arc patch --force ...' when run. NOTE: use "--" before specifying + options! + + If you start an alias with "!", the remainder of the alias will be + invoked as a shell command. For example, if you want to implement + 'arc ls', you can do so like this: + + arc alias ls '!ls' + + You can now run "arc ls" and it will behave like "ls". Of course, this + example is silly and would make your life worse. + + You can not overwrite builtins, including 'alias' itself. The builtin + will always execute, even if it was added after your alias. + + To remove an alias, run: + + arc alias fpatch + + Without any arguments, 'arc alias' will list aliases. + + + amend [--revision revision_id] [--show] + Supports: git, hg + Amend the working copy, synchronizing the local commit message from + Differential. + + Supported in Mercurial 2.2 and newer. + + --revision revision_id + Use the message from a specific revision. If you do not specify + a revision, arc will guess which revision is in the working + copy. + + --show + Show the amended commit message, without modifying the working + copy. + + + anoid + There's only one way to find out... + + + backout + Reverts/backouts on a previous commit. Supports: git, hg + Command is used like this: arc backout <commithash> | <diff revision> + Entering a differential revision will only work if there is only one commit + associated with the revision. This requires your working copy is up to date + and that the commit exists in the working copy. + + + bookmark [options] + bookmark name [start] + Supports: hg + Alias for arc feature. + + --by-status + Sort branches by status instead of time. + + --output format + With 'json', show features in machine-readable JSON format. + + --view-all + Include closed and abandoned revisions. + + + branch [options] + branch name [start] + Supports: git + Alias for arc feature. + + --by-status + Sort branches by status instead of time. + + --output format + With 'json', show features in machine-readable JSON format. + + --view-all + Include closed and abandoned revisions. + + + browse [options] path ... + browse [options] object ... + Supports: git, hg, svn + Open a file or object (like a task or revision) in your web browser. + + $ arc browse README # Open a file in Diffusion. + $ arc browse T123 # View a task. + $ arc browse HEAD # View a symbolic commit. + + Set the 'browser' value using 'arc set-config' to select a browser. If + no browser is set, the command will try to guess which browser to use. + + --branch branch_name + Default branch name to view on server. Defaults to "master". + + --force + Open arguments as paths, even if they do not exist in the + working copy. + + + call-conduit method + Supports: http, https + Allows you to make a raw Conduit method call: + + - Run this command from a working directory. + - Call parameters are REQUIRED and read as a JSON blob from stdin. + - Results are written to stdout as a JSON blob. + + This workflow is primarily useful for writing scripts which integrate + with Phabricator. Examples: + + $ echo '{}' | arc call-conduit conduit.ping + $ echo '{"phid":"PHID-FILE-xxxx"}' | arc call-conduit file.download + + + close task_id [options] + Close a task or otherwise update its status. + + --list-statuses + Show available status options and exit. + + --message comment, -m comment + Provide a comment with your status change. + + --status status, -s status + Specify a new status. Valid status options can be seen with the + `list-statuses` argument. + + + close-revision [options] revision + Supports: git, hg, svn + Close a revision which has been committed (svn) or pushed (git, hg). + You should not normally need to do this: arc commit (svn), arc amend + (git, hg), arc land (git, hg), or repository tracking on the master + remote repository should do it for you. However, if these mechanisms + have failed for some reason you can use this command to manually + change a revision status from "Accepted" to "Closed". + + --finalize + Close only if the repository is untracked and the revision is + accepted. Continue even if the close can't happen. This is a + soft version of '' used by other workflows. + + --quiet + Do not print a success message. + + + commit [--revision revision_id] [--show] + Supports: svn + Commit a revision which has been accepted by a reviewer. + + --revision revision_id + Commit a specific revision. If you do not specify a revision, + arc will look for committable revisions. + + --show + Show the command which would be issued, but do not actually + commit anything. + + + cover [--rev revision] [path ...] + Supports: svn, git, hg + Cover your... professional reputation. Show blame for the lines you + changed in your working copy (svn) or since some commit (hg, git). + This will take a minute because blame takes a minute, especially under + SVN. + + --rev revision + Supports: git, hg + Cover changes since a specific revision. + + + diff [paths] (svn) + diff [commit] (git, hg) + Supports: git, svn, hg + Generate a Differential diff or revision from local changes. + + Under git and mercurial, you can specify a commit (like HEAD^^^ + or master) and Differential will generate a diff against the + merge base of that commit and your current working directory parent. + + Under svn, you can choose to include only some of the modified files + in the working copy in the diff by specifying their paths. If you + omit paths, all changes are included in the diff. + + --add-all, -a + Automatically add all unstaged and uncommitted files to the + commit. + + --advice + Require excuse for lint advice in addition to lint warnings and + errors. + + --allow-untracked + Skip checks for untracked files in the working copy. + + --amend-all + When linting git repositories, amend HEAD with all patches + suggested by lint without prompting. + + --amend-autofixes + When linting git repositories, amend HEAD with autofix patches + suggested by lint without prompting. + + --apply-patches + Apply patches suggested by lint to the working copy without + prompting. + + --base rules + Supports: git, hg + Additional rules for determining base revision. + + --browse + After creating a diff or revision, open it in a web browser. + + --cache bool + 0 to disable lint cache, 1 to enable (default). + + --cc usernames + When creating a revision, add CCs. + + --coverage + Always enable coverage information. + + --create + Always create a new revision. + + --edit + Supports: git, hg + When updating a revision under git, edit revision information + before updating. + + --encoding encoding + Attempt to convert non UTF-8 hunks into specified encoding. + + --excuse excuse + Provide a prepared in advance excuse for any lints/tests shall + they fail. + + --head commit + Supports: git + Specify the end of the commit range. This disables many + Arcanist/Phabricator features which depend on having access to + the working copy. + + --ignore-unsound-tests + Ignore unsound test failures without prompting. + + --json + Emit machine-readable JSON. EXPERIMENTAL! Probably does not + work! + + --less-context + Normally, files are diffed with full context: the entire file + is sent to Differential so reviewers can 'show more' and see + it. If you are making changes to very large files with tens of + thousands of lines, this may not work well. With this flag, a + diff will be created that has only a few lines of context. + + --lintall + Raise all lint warnings, not just those on lines you changed. + + --message message, -m message + When updating a revision, use the specified message instead of + prompting. + + --message-file file, -F file + When creating a revision, read revision information from this + file. + + --never-apply-patches + Never apply patches suggested by lint. + + --no-amend + Never amend commits in the working copy with lint patches. + + --no-coverage + Always disable coverage information. + + --no-diff + Only run lint and unit tests. Intended for internal use. + + --nolint + Do not run lint. + + --nounit + Do not run unit tests. + + --only + Only generate a diff, without running lint, unit tests, or + other auxiliary steps. See also --preview. + + --only-new bool + Display only lint messages not present in the original code. + + --plan-changes + Create or update a revision without requesting a code review. + + --preview + Instead of creating or updating a revision, only create a diff, + which you may later attach to a revision. This still runs lint + unit tests. See also --only. + + --raw + Read diff from stdin, not from the working copy. This disables + many Arcanist/Phabricator features which depend on having + access to the working copy. + + --raw-command command + Generate diff by executing a specified command, not from the + working copy. This disables many Arcanist/Phabricator features + which depend on having access to the working copy. + + --reviewers usernames + When creating a revision, add reviewers. + + --skip-binaries + Do not upload binaries (like images). + + --skip-staging + Do not copy changes to the staging area. + + --uncommitted + Supports: hg + Suppress warning about uncommitted changes. + + --update revision_id + Always update a specific revision. + + --use-commit-message commit, -C commit + Supports: git + Read revision information from a specific commit. + + --verbatim + Supports: hg, git + When creating a revision, try to use the working copy commit + message verbatim, without prompting to edit it. When updating a + revision, update some fields from the local commit message. + + + download file [--as name] [--show] + Supports: filesystems + Download a file to local disk, e.g.: + + $ arc download F33 # Download file 'F33' + + --as name + Save the file with a specific name rather than the default. + + --show + Write file to stdout instead of to disk. + + + export [paths] format (svn) + export [commit_range] format (git, hg) + export --revision revision_id format + export --diff diff_id format + Supports: svn, git, hg + Export the local changeset (or a Differential changeset) to a file, + in some format: git diff (--git), unified diff + (--unified), or arc bundle (--arcbundle path) format. + + --arcbundle file + Export change as an arc bundle. This format can represent all + changes. These bundles can be applied with 'arc patch'. + + --diff diff_id + Instead of exporting changes from the working copy, export them + from a Differential diff. + + --encoding encoding + Attempt to convert non UTF-8 patch into specified encoding. + + --git + Export change as a git patch. This format is more complete than + unified, but less complete than arc bundles. These patches can + be applied with 'git apply' or 'arc patch'. + + --revision revision_id + Instead of exporting changes from the working copy, export them + from a Differential revision. + + --unified + Export change as a unified patch. This format is less complete + than git patches or arc bundles. These patches can be applied + with 'patch' or 'arc patch'. + + + feature [options] + feature name [start] + Supports: git, hg + A wrapper on 'git branch' or 'hg bookmark'. + + Without name, it lists the available branches and their revision + status. + + With name, it creates or checks out a branch. If the branch + name doesn't exist and is in format D123 then the branch of + revision D123 is checked out. Use start to specify where the new + branch will start. Use 'arc.feature.start.default' to set the default + feature start location. + + --by-status + Sort branches by status instead of time. + + --output format + With 'json', show features in machine-readable JSON format. + + --view-all + Include closed and abandoned revisions. + + + flag [object ...] + flag object --clear + flag object [--edit] [--color color] [--note note] + In the first form, list objects you've flagged. You can provide the + names of one or more objects (Maniphest tasks T#, Differential + revisions D#, Diffusion references rXXX???, or PHIDs PHID-XXX-???) + to print only flags for those objects. + + In the second form, clear an existing flag on one object. + + In the third form, create or update a flag on one object. Color + defaults to blue and note to empty, but if you omit both you must + pass --edit. + + --clear + Delete the flag on an object. + + --color color + Set the color of a flag. + + --edit + Edit the flag on an object. + + --note note + Set the note on a flag. + + + get-config [options] -- [name ...] + Supports: cli + Reads an arc configuration option. With no argument, reads all + options. + + With --verbose, shows detailed information about one or more + options. + + --verbose + Show detailed information about options. + + + help [command] + help --full + Supports: english + Shows this help. With command, shows help about a specific + command. + + --full + Print detailed information about each command. + + + install-certificate [uri] + Supports: http, https + Installs Conduit credentials into your ~/.arcrc for the given install + of Phabricator. You need to do this before you can use 'arc', as it + enables 'arc' to link your command-line activity with your account on + the web. Run this command from within a project directory to install + that project's certificate, or specify an explicit URI (like + "https://phabricator.example.com/"). + + + land [options] [ref] + Supports: git, hg + + Publish an accepted revision after review. This command is the last + step in the standard Differential pre-publish code review workflow. + + This command merges and pushes changes associated with an accepted + revision that are currently sitting in ref, which is usually the + name of a local branch. Without ref, the current working copy + state will be used. + + Under Git: branches, tags, and arbitrary commits (detached HEADs) + may be landed. + + Under Mercurial: branches and bookmarks may be landed, but only + onto a target of the same type. See T3855. + + The workflow selects a target branch to land onto and a remote where + the change will be pushed to. + + A target branch is selected by examining these sources in order: + + - the --onto flag; + - the upstream of the current branch, recursively (Git only); + - the arc.land.onto.default configuration setting; + - or by falling back to a standard default: + - "master" in Git; + - "default" in Mercurial. + + A remote is selected by examining these sources in order: + + - the --remote flag; + - the upstream of the current branch, recursively (Git only); + - or by falling back to a standard default: + - "origin" in Git; + - the default remote in Mercurial. + + After selecting a target branch and a remote, the commits which will + be landed are printed. + + With --preview, execution stops here, before the change is + merged. + + The change is merged with the changes in the target branch, + following these rules: + + In repositories with mutable history or with --squash, this will + perform a squash merge (the entire branch will be represented as one + commit after the merge). + + In repositories with immutable history or with --merge, this will + perform a strict merge (a merge commit will always be created, and + local commits will be preserved). + + The resulting commit will be given an up-to-date commit message + describing the final state of the revision in Differential. + + In Git, the merge occurs in a detached HEAD. The local branch + reference (if one exists) is not updated yet. + + With --hold, execution stops here, before the change is pushed. + + The change is pushed into the remote. + + Consulting mystical sources of power, the workflow makes a guess + about what state you wanted to end up in after the process finishes + and the working copy is put into that state. + + The branch which was landed is deleted, unless the --keep-branch + flag was passed or the landing branch is the same as the target + branch. + + + --delete-remote + Delete the feature branch in the remote after landing it. + + --hold + Prepare the change to be pushed, but do not actually push it. + + --keep-branch + Keep the feature branch after pushing changes to the remote (by + default, it is deleted). + + --merge + Supports: git + Perform a --no-ff merge, not a --squash merge. If the project + is marked as having an immutable history, this is the default + behavior. + + --onto master + Land feature branch onto a branch other than the default + ('master' in git, 'default' in hg). You can change the default + by setting 'arc.land.onto.default' with `arc set-config` or for + the entire project in .arcconfig. + + --preview + Prints the commits that would be landed. Does not actually + modify or land the commits. + + --remote origin + Push to a remote other than the default ('origin' in git). + + --revision id + Use the message from a specific revision, rather than inferring + the revision based on branch content. + + --squash + Perform a --squash merge, not a --no-ff merge. If the project + is marked as having a mutable history, this is the default + behavior. + + --update-with-merge + Supports: git + When updating the feature branch, use merge instead of rebase. + This is the default behavior. Setting arc.land.update.default + to 'merge' can also be used to make this the default. + + --update-with-rebase + Supports: git + When updating the feature branch, use rebase instead of merge. + This might make things work better in some cases. Set + arc.land.update.default to 'rebase' to make this the default. + + + liberate [path] + Supports: libphutil + Create or update a libphutil library, generating required metadata + files like init.php. + + --all + Drop the module cache before liberating. This will completely + reanalyze the entire library. Thorough, but slow! + + --force-update + Force the library map to be updated, even in the presence of + lint errors. + + --library-name name + Use a flag for library name rather than awaiting user input. + + + lint [options] [paths] + lint [options] --rev [rev] + Supports: git, svn, hg + Run static analysis on changes to check for mistakes. If no files + are specified, lint will be run on all files which have been modified. + + --amend-all + When linting git repositories, amend HEAD with all patches + suggested by lint without prompting. + + --amend-autofixes + When linting git repositories, amend HEAD with autofix patches + suggested by lint without prompting. + + --apply-patches + Apply patches suggested by lint to the working copy without + prompting. + + --cache bool + 0 to disable cache, 1 to enable. The default value is + determined by 'arc.lint.cache' in configuration, which defaults + to off. See notes in 'arc.lint.cache'. + + --engine classname + Override configured lint engine for this project. + + --everything + Lint all files in the project. + + --lintall + Show all lint warnings, not just those on changed lines. When + paths are specified, this is the default behavior. + + --never-apply-patches + Never apply patches suggested by lint. + + --only-changed + Show lint warnings just on changed lines. When no paths are + specified, this is the default. This differs from only-new in + cases where line modifications introduce lint on other + unmodified lines. + + --only-new bool + Supports: git, hg + Display only messages not present in the original code. + + --outfile path + Output the linter results to a file. Defaults to stdout. + + --output format + With 'summary', show lint warnings in a more compact format. + With 'json', show lint warnings in machine-readable JSON + format. With 'none', show no lint warnings. With 'compiler', + show lint warnings in suitable for your editor. With 'xml', + show lint warnings in the Checkstyle XML format. + + --rev revision + Supports: git, hg + Lint changes since a specific revision. + + --severity string + Set minimum message severity. One of: 'advice', 'autofix', + 'warning', 'error', 'disabled'. Defaults to 'advice'. + + + linters [options] [name] + Supports: cli + List the available and configured linters, with information about + what they do and which versions are installed. + + if name is provided, the linter with that name will be displayed. + + --search search + Search for linters. Search is case-insensitive, and is + performedagainst name and description of each linter. + + --verbose + Show detailed information, including options. + + + list + Supports: git, svn, hg + List your open Differential revisions. + + + paste [--title title] [--lang language] [--json] + paste id [--json] + Supports: text + Share and grab text using the Paste application. To create a paste, + use stdin to provide the text: + + $ cat list_of_ducks.txt | arc paste + + To retrieve a paste, specify the paste ID: + + $ arc paste P123 + + --json + Output in JSON format. + + --lang language + Language for syntax highlighting. + + --title title + Title for the paste. + + + patch D12345 + patch --revision revision_id + patch --diff diff_id + patch --patch file + patch --arcbundle bundlefile + Supports: git, svn, hg + Apply the changes in a Differential revision, patchfile, or arc + bundle to the working copy. + + --arcbundle bundlefile + Apply changes from an arc bundle generated with 'arc export'. + + --diff diff_id + Apply changes from a Differential diff. Normally you want to + use --revision to get the most recent changes, but you can + specifically apply an out-of-date diff or a diff which was + never attached to a revision by using this flag. + + --encoding encoding + Attempt to convert non UTF-8 patch into specified encoding. + + --force + Do not run any sanity checks. + + --nobranch + Supports: git, hg + Normally, a new branch (git) or bookmark (hg) is created and + then the patch is applied and committed in the new + branch/bookmark. This flag cherry-picks the resultant commit + onto the original branch and deletes the temporary branch. + + --nocommit + Supports: git, hg + Normally under git/hg, if the patch is successful, the changes + are committed to the working copy. This flag prevents the + commit. + + --patch patchfile + Apply changes from a git patchfile or unified patchfile. + + --revision revision_id + Apply changes from a Differential revision, using the most + recent diff that has been attached to it. You can run 'arc + patch D12345' as a shorthand. + + --skip-dependencies + Supports: git, hg + Normally, if a patch has dependencies that are not present in + the working copy, arc tries to apply them as well. This flag + prevents such work. + + --update + Supports: git, svn, hg + Update the local working copy before applying the patch. + + + revert + Please use arc backout instead + + + set-config [options] -- name value + Supports: cli + Sets an arc configuration option. + + Options are either user (apply to all arc commands you invoke + from the current user) or local (apply only to the current working + copy). By default, user configuration is written. Use --local + to write local configuration. + + User values are written to '~/.arcrc' on Linux and Mac OS X, and an + undisclosed location on Windows. Local values are written to an arc + directory under either .git, .hg, or .svn as appropriate. + + --local + Set a local config value instead of a user one. + + + shell-complete --current N -- [argv] + Supports: bash, etc. + Implements shell completion. To use shell completion, source the + appropriate script from 'resources/shell/' in your .shellrc. + + --current cursor_position + Current term in the argument list being completed. + + + start object + Start tracking work in Phrequent. + + + stop [--note note] [objects] + Stop tracking work in Phrequent. + + --note note + A note to attach to the tracked time. + + + tasks [options] + View all assigned tasks. + + --limit n + Limit the amount of tasks outputted, default is all. + + --order task_order + Arrange tasks based on priority, created, or modified, default + is priority. + + --owner username + Only show tasks assigned to the given username, also accepts + @all to show all, default is you. + + --status task_status + Show tasks that are open or closed, default is open. + + --unassigned + Only show tasks that are not assigned (upforgrabs). + + + time + Show what you're currently tracking in Phrequent. + + + todo summary [options] + Quickly create a task for yourself. + + --browse + After creating the task, open it in a web browser. + + --cc cc, -C cc + Other users to CC on the new task. + + --project project + Projects to assign to the task. + + + unit [options] [paths] + unit [options] --rev [rev] + Supports: git, svn, hg + Run unit tests that cover specified paths. If no paths are specified, + unit tests covering all modified files will be run. + + --coverage + Always enable coverage information. + + --detailed-coverage + Show a detailed coverage report on the CLI. Implies --coverage. + + --engine classname + Override configured unit engine for this project. + + --everything + Run every test. + + --json + Report results in JSON format. + + --no-coverage + Always disable coverage information. + + --output format + With 'full', show full pretty report (Default). With 'json', + report results in JSON format. With 'ugly', use uglier (but + more efficient) JSON formatting. With 'none', don't print + results. + + --rev revision + Supports: git, hg + Run unit tests covering changes since a specific revision. + + --target phid + (PROTOTYPE) Record a copy of the test results on the specified + Harbormaster build target. + + --ugly + With --json, use uglier (but more efficient) formatting. + + + upgrade + Supports: cli + Upgrade arcanist and libphutil to the latest versions. + + + upload file [file ...] [--json] + Supports: filesystems + Upload a file from local disk. + + --json + Output upload information in JSON format. + + --temporary + Mark the file as temporary. Temporary files will be deleted + automatically after 24 hours. + + + version [options] + Supports: cli + Shows the current version of arcanist. + + + which [options] (svn) + which [options] [commit] (hg, git) + Supports: svn, git, hg + Shows which repository the current working copy corresponds to, + which commits 'arc diff' will select, and which revision is in + the working copy (or which revisions, if more than one matches). + + --any-status + Show committed and abandoned revisions. + + --base rules + Supports: git, hg + Additional rules for determining base revision. + + --head commit + Supports: git + Specify the end of the commit range to select. + + --show-base + Supports: git, hg + Print base commit only and exit. + + +OPTION REFERENCE + + --trace + Debugging command. Shows underlying commands as they are executed, + and full stack traces when exceptions are thrown. + + --no-ansi + Output in plain ASCII text only, without color or style. + + --ansi + Use formatting even in environments which probably don't support it. + Example: arc --ansi unit | less -r + + --load-phutil-library=/path/to/library + Ignore libraries listed in .arcconfig and explicitly load specified + libraries instead. Mostly useful for Arcanist development. + + --conduit-uri uri + Ignore configured Conduit URI and use an explicit one instead. Mostly + useful for Arcanist development. + + --conduit-token token + Ignore configured credentials and use an explicit API token instead. + + --conduit-version version + Ignore software version and claim to be running some other version + instead. Mostly useful for Arcanist development. May cause bad things + to happen. + + --conduit-timeout timeout + Override the default Conduit timeout. Specified in seconds. + + --config key=value + Specify a runtime configuration value. This will take precedence + over static values, and only affect the current arcanist invocation. + + --skip-arcconfig + Skip the working copy configuration file + + --arcrc-file filename + Use provided file instead of ~/.arcrc. diff -Nru phabricator-0~git20200925/debian/doc/arcanist.pod phabricator-0~git20220903/debian/doc/arcanist.pod --- phabricator-0~git20200925/debian/doc/arcanist.pod 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/doc/arcanist.pod 2022-09-08 09:46:51.000000000 +0000 @@ -0,0 +1,2884 @@ + +=head1 NAME + + +B<arc> - arcanist, a code review and revision management utility + + +=head1 SYNOPSIS + + +B<arc> I<command> [I<options>] [I<args>] +This help file provides a detailed command reference. + + +=head1 COMMAND REFERENCE + + + +B<alias> + +B<alias> I<command> + +B<alias> I<command> I<target> -- [I<options>] + +=over + +Supports: cli +Create an alias from I<command> to I<target> (optionally, with +I<options>). For example: + + arc alias fpatch patch -- --force + +...will create a new 'arc' command, 'arc fpatch', which invokes +'arc patch --force ...' when run. NOTE: use "--" before specifying +options! + +If you start an alias with "!", the remainder of the alias will be +invoked as a shell command. For example, if you want to implement +'arc ls', you can do so like this: + + arc alias ls '!ls' + +You can now run "arc ls" and it will behave like "ls". Of course, this +example is silly and would make your life worse. + +You can not overwrite builtins, including 'alias' itself. The builtin +will always execute, even if it was added after your alias. + +To remove an alias, run: + + arc alias fpatch + +Without any arguments, 'arc alias' will list aliases. + + +=back + +B<amend> [--revision I<revision_id>] [--show] + +=over + +Supports: git, hg +Amend the working copy, synchronizing the local commit message from +Differential. + +Supported in Mercurial 2.2 and newer. + + +=over + +=item I<--revision> I<revision_id> + +=back + + +=over + +Use the message from a specific revision. If you do not specify +a revision, arc will guess which revision is in the working +copy. + +=back + + +=over + +=item I<--show> + +=back + + +=over + +Show the amended commit message, without modifying the working +copy. + +=back + + +=back + +B<anoid> + +=over + +There's only one way to find out... + + +=back + +B<backout> + +=over + +Reverts/backouts on a previous commit. Supports: git, hg + +=over + +Command is used like this: arc backout <commithash> | <diff revision> +Entering a differential revision will only work if there is only one commit +associated with the revision. This requires your working copy is up to date +and that the commit exists in the working copy. + +=back + + +=back + +B<bookmark> [I<options>] + +B<bookmark> I<name> [I<start>] + +=over + +Supports: hg +Alias for arc feature. + + +=over + +=item I<--by-status> + +=back + + +=over + +Sort branches by status instead of time. + +=back + + +=over + +=item I<--output> I<format> + +=back + + +=over + +With 'json', show features in machine-readable JSON format. + +=back + + +=over + +=item I<--view-all> + +=back + + +=over + +Include closed and abandoned revisions. + +=back + + +=back + +B<branch> [I<options>] + +B<branch> I<name> [I<start>] + +=over + +Supports: git +Alias for arc feature. + + +=over + +=item I<--by-status> + +=back + + +=over + +Sort branches by status instead of time. + +=back + + +=over + +=item I<--output> I<format> + +=back + + +=over + +With 'json', show features in machine-readable JSON format. + +=back + + +=over + +=item I<--view-all> + +=back + + +=over + +Include closed and abandoned revisions. + +=back + + +=back + +B<browse> [I<options>] I<path> ... + +B<browse> [I<options>] I<object> ... + +=over + +Supports: git, hg, svn +Open a file or object (like a task or revision) in your web browser. + + $ arc browse README # Open a file in Diffusion. + $ arc browse T123 # View a task. + $ arc browse HEAD # View a symbolic commit. + +Set the 'browser' value using 'arc set-config' to select a browser. If +no browser is set, the command will try to guess which browser to use. + + +=over + +=item I<--branch> I<branch_name> + +=back + + +=over + +Default branch name to view on server. Defaults to "master". + +=back + + +=over + +=item I<--force> + +=back + + +=over + +Open arguments as paths, even if they do not exist in the +working copy. + +=back + + +=back + +B<call-conduit> I<method> + +=over + +Supports: http, https +Allows you to make a raw Conduit method call: + + - Run this command from a working directory. + - Call parameters are REQUIRED and read as a JSON blob from stdin. + - Results are written to stdout as a JSON blob. + +This workflow is primarily useful for writing scripts which integrate +with Phabricator. Examples: + + $ echo '{}' | arc call-conduit conduit.ping + $ echo '{"phid":"PHID-FILE-xxxx"}' | arc call-conduit file.download + + +=back + +B<close> I<task_id> [I<options>] + Close a task or otherwise update its status. + + +=over + +=item I<--list-statuses> + +=back + + +=over + +Show available status options and exit. + +=back + + +=over + +=item I<--message> I<comment>, I<-m> I<comment> + +=back + + +=over + +Provide a comment with your status change. + +=back + + +=over + +=item I<--status> I<status>, I<-s> I<status> + +=back + + +=over + +Specify a new status. Valid status options can be seen with the +`list-statuses` argument. + +=back + + + +B<close-revision> [I<options>] I<revision> + +=over + +Supports: git, hg, svn +Close a revision which has been committed (svn) or pushed (git, hg). +You should not normally need to do this: arc commit (svn), arc amend +(git, hg), arc land (git, hg), or repository tracking on the master +remote repository should do it for you. However, if these mechanisms +have failed for some reason you can use this command to manually +change a revision status from "Accepted" to "Closed". + + +=over + +=item I<--finalize> + +=back + + +=over + +Close only if the repository is untracked and the revision is +accepted. Continue even if the close can't happen. This is a +soft version of '' used by other workflows. + +=back + + +=over + +=item I<--quiet> + +=back + + +=over + +Do not print a success message. + +=back + + +=back + +B<commit> [--revision I<revision_id>] [--show] + +=over + +Supports: svn +Commit a revision which has been accepted by a reviewer. + + +=over + +=item I<--revision> I<revision_id> + +=back + + +=over + +Commit a specific revision. If you do not specify a revision, +arc will look for committable revisions. + +=back + + +=over + +=item I<--show> + +=back + + +=over + +Show the command which would be issued, but do not actually +commit anything. + +=back + + +=back + +B<cover> [--rev I<revision>] [I<path> ...] + +=over + +Supports: svn, git, hg +Cover your... professional reputation. Show blame for the lines you +changed in your working copy (svn) or since some commit (hg, git). +This will take a minute because blame takes a minute, especially under +SVN. + + +=over + +=item I<--rev> I<revision> + +=back + + +=over + +Supports: git, hg +Cover changes since a specific revision. + +=back + + +=back + +B<diff> [I<paths>] (svn) + +B<diff> [I<commit>] (git, hg) + +=over + +Supports: git, svn, hg +Generate a Differential diff or revision from local changes. + +Under git and mercurial, you can specify a commit (like I<HEAD^^^> +or I<master>) and Differential will generate a diff against the +merge base of that commit and your current working directory parent. + +Under svn, you can choose to include only some of the modified files +in the working copy in the diff by specifying their paths. If you +omit paths, all changes are included in the diff. + + +=over + +=item I<--add-all>, I<-a> + +=back + + +=over + +Automatically add all unstaged and uncommitted files to the +commit. + +=back + + +=over + +=item I<--advice> + +=back + + +=over + +Require excuse for lint advice in addition to lint warnings and +errors. + +=back + + +=over + +=item I<--allow-untracked> + +=back + + +=over + +Skip checks for untracked files in the working copy. + +=back + + +=over + +=item I<--amend-all> + +=back + + +=over + +When linting git repositories, amend HEAD with all patches +suggested by lint without prompting. + +=back + + +=over + +=item I<--amend-autofixes> + +=back + + +=over + +When linting git repositories, amend HEAD with autofix patches +suggested by lint without prompting. + +=back + + +=over + +=item I<--apply-patches> + +=back + + +=over + +Apply patches suggested by lint to the working copy without +prompting. + +=back + + +=over + +=item I<--base> I<rules> + +=back + + +=over + +Supports: git, hg +Additional rules for determining base revision. + +=back + + +=over + +=item I<--browse> + +=back + + +=over + +After creating a diff or revision, open it in a web browser. + +=back + + +=over + +=item I<--cache> I<bool> + +=back + + 0 to disable lint cache, 1 to enable (default). + + +=over + +=item I<--cc> I<usernames> + +=back + + +=over + +When creating a revision, add CCs. + +=back + + +=over + +=item I<--coverage> + +=back + + +=over + +Always enable coverage information. + +=back + + +=over + +=item I<--create> + +=back + + +=over + +Always create a new revision. + +=back + + +=over + +=item I<--edit> + +=back + + +=over + +Supports: git, hg +When updating a revision under git, edit revision information +before updating. + +=back + + +=over + +=item I<--encoding> I<encoding> + +=back + + +=over + +Attempt to convert non UTF-8 hunks into specified encoding. + +=back + + +=over + +=item I<--excuse> I<excuse> + +=back + + +=over + +Provide a prepared in advance excuse for any lints/tests shall +they fail. + +=back + + +=over + +=item I<--head> I<commit> + +=back + + +=over + +Supports: git +Specify the end of the commit range. This disables many +Arcanist/Phabricator features which depend on having access to +the working copy. + +=back + + +=over + +=item I<--ignore-unsound-tests> + +=back + + +=over + +Ignore unsound test failures without prompting. + +=back + + +=over + +=item I<--json> + +=back + + +=over + +Emit machine-readable JSON. EXPERIMENTAL! Probably does not +work! + +=back + + +=over + +=item I<--less-context> + +=back + + +=over + +Normally, files are diffed with full context: the entire file +is sent to Differential so reviewers can 'show more' and see +it. If you are making changes to very large files with tens of +thousands of lines, this may not work well. With this flag, a +diff will be created that has only a few lines of context. + +=back + + +=over + +=item I<--lintall> + +=back + + +=over + +Raise all lint warnings, not just those on lines you changed. + +=back + + +=over + +=item I<--message> I<message>, I<-m> I<message> + +=back + + +=over + +When updating a revision, use the specified message instead of +prompting. + +=back + + +=over + +=item I<--message-file> I<file>, I<-F> I<file> + +=back + + +=over + +When creating a revision, read revision information from this +file. + +=back + + +=over + +=item I<--never-apply-patches> + +=back + + +=over + +Never apply patches suggested by lint. + +=back + + +=over + +=item I<--no-amend> + +=back + + +=over + +Never amend commits in the working copy with lint patches. + +=back + + +=over + +=item I<--no-coverage> + +=back + + +=over + +Always disable coverage information. + +=back + + +=over + +=item I<--no-diff> + +=back + + +=over + +Only run lint and unit tests. Intended for internal use. + +=back + + +=over + +=item I<--nolint> + +=back + + +=over + +Do not run lint. + +=back + + +=over + +=item I<--nounit> + +=back + + +=over + +Do not run unit tests. + +=back + + +=over + +=item I<--only> + +=back + + +=over + +Only generate a diff, without running lint, unit tests, or +other auxiliary steps. See also --preview. + +=back + + +=over + +=item I<--only-new> I<bool> + +=back + + +=over + +Display only lint messages not present in the original code. + +=back + + +=over + +=item I<--plan-changes> + +=back + + +=over + +Create or update a revision without requesting a code review. + +=back + + +=over + +=item I<--preview> + +=back + + +=over + +Instead of creating or updating a revision, only create a diff, +which you may later attach to a revision. This still runs lint +unit tests. See also --only. + +=back + + +=over + +=item I<--raw> + +=back + + +=over + +Read diff from stdin, not from the working copy. This disables +many Arcanist/Phabricator features which depend on having +access to the working copy. + +=back + + +=over + +=item I<--raw-command> I<command> + +=back + + +=over + +Generate diff by executing a specified command, not from the +working copy. This disables many Arcanist/Phabricator features +which depend on having access to the working copy. + +=back + + +=over + +=item I<--reviewers> I<usernames> + +=back + + +=over + +When creating a revision, add reviewers. + +=back + + +=over + +=item I<--skip-binaries> + +=back + + +=over + +Do not upload binaries (like images). + +=back + + +=over + +=item I<--skip-staging> + +=back + + +=over + +Do not copy changes to the staging area. + +=back + + +=over + +=item I<--uncommitted> + +=back + + +=over + +Supports: hg +Suppress warning about uncommitted changes. + +=back + + +=over + +=item I<--update> I<revision_id> + +=back + + +=over + +Always update a specific revision. + +=back + + +=over + +=item I<--use-commit-message> I<commit>, I<-C> I<commit> + +=back + + +=over + +Supports: git +Read revision information from a specific commit. + +=back + + +=over + +=item I<--verbatim> + +=back + + +=over + +Supports: hg, git +When creating a revision, try to use the working copy commit +message verbatim, without prompting to edit it. When updating a +revision, update some fields from the local commit message. + +=back + + +=back + +B<download> I<file> [--as I<name>] [--show] + +=over + +Supports: filesystems +Download a file to local disk, e.g.: + + $ arc download F33 # Download file 'F33' + + +=over + +=item I<--as> I<name> + +=back + + +=over + +Save the file with a specific name rather than the default. + +=back + + +=over + +=item I<--show> + +=back + + +=over + +Write file to stdout instead of to disk. + +=back + + +=back + +B<export> [I<paths>] I<format> (svn) + +B<export> [I<commit_range>] I<format> (git, hg) + +B<export> I<--revision> I<revision_id> I<format> + +B<export> I<--diff> I<diff_id> I<format> + +=over + +Supports: svn, git, hg +Export the local changeset (or a Differential changeset) to a file, +in some I<format>: git diff (I<--git>), unified diff +(I<--unified>), or arc bundle (I<--arcbundle> I<path>) format. + + +=over + +=item I<--arcbundle> I<file> + +=back + + +=over + +Export change as an arc bundle. This format can represent all +changes. These bundles can be applied with 'arc patch'. + +=back + + +=over + +=item I<--diff> I<diff_id> + +=back + + +=over + +Instead of exporting changes from the working copy, export them +from a Differential diff. + +=back + + +=over + +=item I<--encoding> I<encoding> + +=back + + +=over + +Attempt to convert non UTF-8 patch into specified encoding. + +=back + + +=over + +=item I<--git> + +=back + + +=over + +Export change as a git patch. This format is more complete than +unified, but less complete than arc bundles. These patches can +be applied with 'git apply' or 'arc patch'. + +=back + + +=over + +=item I<--revision> I<revision_id> + +=back + + +=over + +Instead of exporting changes from the working copy, export them +from a Differential revision. + +=back + + +=over + +=item I<--unified> + +=back + + +=over + +Export change as a unified patch. This format is less complete +than git patches or arc bundles. These patches can be applied +with 'patch' or 'arc patch'. + +=back + + +=back + +B<feature> [I<options>] + +B<feature> I<name> [I<start>] + +=over + +Supports: git, hg +A wrapper on 'git branch' or 'hg bookmark'. + +Without I<name>, it lists the available branches and their revision +status. + +With I<name>, it creates or checks out a branch. If the branch +I<name> doesn't exist and is in format D123 then the branch of +revision D123 is checked out. Use I<start> to specify where the new +branch will start. Use 'arc.feature.start.default' to set the default +feature start location. + + +=over + +=item I<--by-status> + +=back + + +=over + +Sort branches by status instead of time. + +=back + + +=over + +=item I<--output> I<format> + +=back + + +=over + +With 'json', show features in machine-readable JSON format. + +=back + + +=over + +=item I<--view-all> + +=back + + +=over + +Include closed and abandoned revisions. + +=back + + +=back + +B<flag> [I<object> ...] + +B<flag> I<object> --clear + +B<flag> I<object> [--edit] [--color I<color>] [--note I<note>] + +=over + +In the first form, list objects you've flagged. You can provide the +names of one or more objects (Maniphest tasks T#, Differential +revisions D#, Diffusion references rXXX???, or PHIDs PHID-XXX-???) +to print only flags for those objects. + +In the second form, clear an existing flag on one object. + +In the third form, create or update a flag on one object. Color +defaults to blue and note to empty, but if you omit both you must +pass --edit. + + +=over + +=item I<--clear> + +=back + + +=over + +Delete the flag on an object. + +=back + + +=over + +=item I<--color> I<color> + +=back + + +=over + +Set the color of a flag. + +=back + + +=over + +=item I<--edit> + +=back + + +=over + +Edit the flag on an object. + +=back + + +=over + +=item I<--note> I<note> + +=back + + +=over + +Set the note on a flag. + +=back + + +=back + +B<get-config> [I<options>] -- [I<name> ...] + +=over + +Supports: cli +Reads an arc configuration option. With no argument, reads all +options. + +With I<--verbose>, shows detailed information about one or more +options. + + +=over + +=item I<--verbose> + +=back + + +=over + +Show detailed information about options. + +=back + + +=back + +B<help> [I<command>] + +B<help> --full + +=over + +Supports: english +Shows this help. With I<command>, shows help about a specific +command. + + +=over + +=item I<--full> + +=back + + +=over + +Print detailed information about each command. + +=back + + +=back + +B<install-certificate> [uri] + +=over + +Supports: http, https +Installs Conduit credentials into your ~/.arcrc for the given install +of Phabricator. You need to do this before you can use 'arc', as it +enables 'arc' to link your command-line activity with your account on +the web. Run this command from within a project directory to install +that project's certificate, or specify an explicit URI (like +"https://phabricator.example.com/"). + + +=back + +B<land> [I<options>] [I<ref>] + +=over + +Supports: git, hg + +Publish an accepted revision after review. This command is the last +step in the standard Differential pre-publish code review workflow. + +This command merges and pushes changes associated with an accepted +revision that are currently sitting in I<ref>, which is usually the +name of a local branch. Without I<ref>, the current working copy +state will be used. + +Under Git: branches, tags, and arbitrary commits (detached HEADs) +may be landed. + +Under Mercurial: branches and bookmarks may be landed, but only +onto a target of the same type. See T3855. + +The workflow selects a target branch to land onto and a remote where +the change will be pushed to. + +A target branch is selected by examining these sources in order: + + - the B<--onto> flag; + - the upstream of the current branch, recursively (Git only); + - the I<arc.land.onto.default> configuration setting; + - or by falling back to a standard default: + - "master" in Git; + - "default" in Mercurial. + +A remote is selected by examining these sources in order: + + - the B<--remote> flag; + - the upstream of the current branch, recursively (Git only); + - or by falling back to a standard default: + - "origin" in Git; + - the default remote in Mercurial. + +After selecting a target branch and a remote, the commits which will +be landed are printed. + +With B<--preview>, execution stops here, before the change is +merged. + +The change is merged with the changes in the target branch, +following these rules: + +In repositories with mutable history or with B<--squash>, this will +perform a squash merge (the entire branch will be represented as one +commit after the merge). + +In repositories with immutable history or with B<--merge>, this will +perform a strict merge (a merge commit will always be created, and +local commits will be preserved). + +The resulting commit will be given an up-to-date commit message +describing the final state of the revision in Differential. + +In Git, the merge occurs in a detached HEAD. The local branch +reference (if one exists) is not updated yet. + +With B<--hold>, execution stops here, before the change is pushed. + +The change is pushed into the remote. + +Consulting mystical sources of power, the workflow makes a guess +about what state you wanted to end up in after the process finishes +and the working copy is put into that state. + +The branch which was landed is deleted, unless the B<--keep-branch> +flag was passed or the landing branch is the same as the target +branch. + + + +=over + +=item I<--delete-remote> + +=back + + +=over + +Delete the feature branch in the remote after landing it. + +=back + + +=over + +=item I<--hold> + +=back + + +=over + +Prepare the change to be pushed, but do not actually push it. + +=back + + +=over + +=item I<--keep-branch> + +=back + + +=over + +Keep the feature branch after pushing changes to the remote (by +default, it is deleted). + +=back + + +=over + +=item I<--merge> + +=back + + +=over + +Supports: git +Perform a --no-ff merge, not a --squash merge. If the project +is marked as having an immutable history, this is the default +behavior. + +=back + + +=over + +=item I<--onto> I<master> + +=back + + +=over + +Land feature branch onto a branch other than the default +('master' in git, 'default' in hg). You can change the default +by setting 'arc.land.onto.default' with `arc set-config` or for +the entire project in .arcconfig. + +=back + + +=over + +=item I<--preview> + +=back + + +=over + +Prints the commits that would be landed. Does not actually +modify or land the commits. + +=back + + +=over + +=item I<--remote> I<origin> + +=back + + +=over + +Push to a remote other than the default ('origin' in git). + +=back + + +=over + +=item I<--revision> I<id> + +=back + + +=over + +Use the message from a specific revision, rather than inferring +the revision based on branch content. + +=back + + +=over + +=item I<--squash> + +=back + + +=over + +Perform a --squash merge, not a --no-ff merge. If the project +is marked as having a mutable history, this is the default +behavior. + +=back + + +=over + +=item I<--update-with-merge> + +=back + + +=over + +Supports: git +When updating the feature branch, use merge instead of rebase. +This is the default behavior. Setting arc.land.update.default +to 'merge' can also be used to make this the default. + +=back + + +=over + +=item I<--update-with-rebase> + +=back + + +=over + +Supports: git +When updating the feature branch, use rebase instead of merge. +This might make things work better in some cases. Set +arc.land.update.default to 'rebase' to make this the default. + +=back + + +=back + +B<liberate> [I<path>] + +=over + +Supports: libphutil +Create or update a libphutil library, generating required metadata +files like I<init>.php. + + +=over + +=item I<--all> + +=back + + +=over + +Drop the module cache before liberating. This will completely +reanalyze the entire library. Thorough, but slow! + +=back + + +=over + +=item I<--force-update> + +=back + + +=over + +Force the library map to be updated, even in the presence of +lint errors. + +=back + + +=over + +=item I<--library-name> I<name> + +=back + + +=over + +Use a flag for library name rather than awaiting user input. + +=back + + +=back + +B<lint> [I<options>] [I<paths>] + +B<lint> [I<options>] --rev [I<rev>] + +=over + +Supports: git, svn, hg +Run static analysis on changes to check for mistakes. If no files +are specified, lint will be run on all files which have been modified. + + +=over + +=item I<--amend-all> + +=back + + +=over + +When linting git repositories, amend HEAD with all patches +suggested by lint without prompting. + +=back + + +=over + +=item I<--amend-autofixes> + +=back + + +=over + +When linting git repositories, amend HEAD with autofix patches +suggested by lint without prompting. + +=back + + +=over + +=item I<--apply-patches> + +=back + + +=over + +Apply patches suggested by lint to the working copy without +prompting. + +=back + + +=over + +=item I<--cache> I<bool> + +=back + + 0 to disable cache, 1 to enable. The default value is + determined by 'arc.lint.cache' in configuration, which defaults + to off. See notes in 'arc.lint.cache'. + + +=over + +=item I<--engine> I<classname> + +=back + + +=over + +Override configured lint engine for this project. + +=back + + +=over + +=item I<--everything> + +=back + + +=over + +Lint all files in the project. + +=back + + +=over + +=item I<--lintall> + +=back + + +=over + +Show all lint warnings, not just those on changed lines. When +paths are specified, this is the default behavior. + +=back + + +=over + +=item I<--never-apply-patches> + +=back + + +=over + +Never apply patches suggested by lint. + +=back + + +=over + +=item I<--only-changed> + +=back + + +=over + +Show lint warnings just on changed lines. When no paths are +specified, this is the default. This differs from only-new in +cases where line modifications introduce lint on other +unmodified lines. + +=back + + +=over + +=item I<--only-new> I<bool> + +=back + + +=over + +Supports: git, hg +Display only messages not present in the original code. + +=back + + +=over + +=item I<--outfile> I<path> + +=back + + +=over + +Output the linter results to a file. Defaults to stdout. + +=back + + +=over + +=item I<--output> I<format> + +=back + + +=over + +With 'summary', show lint warnings in a more compact format. +With 'json', show lint warnings in machine-readable JSON +format. With 'none', show no lint warnings. With 'compiler', +show lint warnings in suitable for your editor. With 'xml', +show lint warnings in the Checkstyle XML format. + +=back + + +=over + +=item I<--rev> I<revision> + +=back + + +=over + +Supports: git, hg +Lint changes since a specific revision. + +=back + + +=over + +=item I<--severity> I<string> + +=back + + +=over + +Set minimum message severity. One of: 'advice', 'autofix', +'warning', 'error', 'disabled'. Defaults to 'advice'. + +=back + + +=back + +B<linters> [I<options>] [I<name>] + +=over + +Supports: cli +List the available and configured linters, with information about +what they do and which versions are installed. + +if I<name> is provided, the linter with that name will be displayed. + + +=over + +=item I<--search> I<search> + +=back + + +=over + +Search for linters. Search is case-insensitive, and is +performedagainst name and description of each linter. + +=back + + +=over + +=item I<--verbose> + +=back + + +=over + +Show detailed information, including options. + +=back + + +=back + +B<list> + +=over + +Supports: git, svn, hg +List your open Differential revisions. + + +=back + +B<paste> [--title I<title>] [--lang I<language>] [--json] + +B<paste> I<id> [--json] + +=over + +Supports: text +Share and grab text using the Paste application. To create a paste, +use stdin to provide the text: + + $ cat list_of_ducks.txt | arc paste + +To retrieve a paste, specify the paste ID: + + $ arc paste P123 + + +=over + +=item I<--json> + +=back + + +=over + +Output in JSON format. + +=back + + +=over + +=item I<--lang> I<language> + +=back + + +=over + +Language for syntax highlighting. + +=back + + +=over + +=item I<--title> I<title> + +=back + + +=over + +Title for the paste. + +=back + + +=back + +B<patch> I<D12345> + +B<patch> I<--revision> I<revision_id> + +B<patch> I<--diff> I<diff_id> + +B<patch> I<--patch> I<file> + +B<patch> I<--arcbundle> I<bundlefile> + +=over + +Supports: git, svn, hg +Apply the changes in a Differential revision, patchfile, or arc +bundle to the working copy. + + +=over + +=item I<--arcbundle> I<bundlefile> + +=back + + +=over + +Apply changes from an arc bundle generated with 'arc export'. + +=back + + +=over + +=item I<--diff> I<diff_id> + +=back + + +=over + +Apply changes from a Differential diff. Normally you want to +use --revision to get the most recent changes, but you can +specifically apply an out-of-date diff or a diff which was +never attached to a revision by using this flag. + +=back + + +=over + +=item I<--encoding> I<encoding> + +=back + + +=over + +Attempt to convert non UTF-8 patch into specified encoding. + +=back + + +=over + +=item I<--force> + +=back + + +=over + +Do not run any sanity checks. + +=back + + +=over + +=item I<--nobranch> + +=back + + +=over + +Supports: git, hg +Normally, a new branch (git) or bookmark (hg) is created and +then the patch is applied and committed in the new +branch/bookmark. This flag cherry-picks the resultant commit +onto the original branch and deletes the temporary branch. + +=back + + +=over + +=item I<--nocommit> + +=back + + +=over + +Supports: git, hg +Normally under git/hg, if the patch is successful, the changes +are committed to the working copy. This flag prevents the +commit. + +=back + + +=over + +=item I<--patch> I<patchfile> + +=back + + +=over + +Apply changes from a git patchfile or unified patchfile. + +=back + + +=over + +=item I<--revision> I<revision_id> + +=back + + +=over + +Apply changes from a Differential revision, using the most +recent diff that has been attached to it. You can run 'arc +patch D12345' as a shorthand. + +=back + + +=over + +=item I<--skip-dependencies> + +=back + + +=over + +Supports: git, hg +Normally, if a patch has dependencies that are not present in +the working copy, arc tries to apply them as well. This flag +prevents such work. + +=back + + +=over + +=item I<--update> + +=back + + +=over + +Supports: git, svn, hg +Update the local working copy before applying the patch. + +=back + + +=back + +B<revert> +Please use arc backout instead + + + +B<set-config> [I<options>] -- I<name> I<value> + +=over + +Supports: cli +Sets an arc configuration option. + +Options are either user (apply to all arc commands you invoke +from the current user) or local (apply only to the current working +copy). By default, user configuration is written. Use I<--local> +to write local configuration. + +User values are written to '~/.arcrc' on Linux and Mac OS X, and an +undisclosed location on Windows. Local values are written to an arc +directory under either .git, .hg, or .svn as appropriate. + + +=over + +=item I<--local> + +=back + + +=over + +Set a local config value instead of a user one. + +=back + + +=back + +B<shell-complete> I<--current> I<N> -- [I<argv>] + +=over + +Supports: bash, etc. +Implements shell completion. To use shell completion, source the +appropriate script from 'resources/shell/' in your .shellrc. + + +=over + +=item I<--current> I<cursor_position> + +=back + + +=over + +Current term in the argument list being completed. + +=back + + +=back + +B<start> I<object> + +=over + +Start tracking work in Phrequent. + + +=back + +B<stop> [--note I<note>] [I<objects>] + +=over + +Stop tracking work in Phrequent. + + +=over + +=item I<--note> I<note> + +=back + + +=over + +A note to attach to the tracked time. + +=back + + +=back + +B<tasks> [I<options>] + View all assigned tasks. + + +=over + +=item I<--limit> I<n> + +=back + + +=over + +Limit the amount of tasks outputted, default is all. + +=back + + +=over + +=item I<--order> I<task_order> + +=back + + +=over + +Arrange tasks based on priority, created, or modified, default +is priority. + +=back + + +=over + +=item I<--owner> I<username> + +=back + + +=over + +Only show tasks assigned to the given username, also accepts +@all to show all, default is you. + +=back + + +=over + +=item I<--status> I<task_status> + +=back + + +=over + +Show tasks that are open or closed, default is open. + +=back + + +=over + +=item I<--unassigned> + +=back + + +=over + +Only show tasks that are not assigned (upforgrabs). + +=back + + + +B<time> + +=over + +Show what you're currently tracking in Phrequent. + + +=back + +B<todo> I<summary> [I<options>] + Quickly create a task for yourself. + + +=over + +=item I<--browse> + +=back + + +=over + +After creating the task, open it in a web browser. + +=back + + +=over + +=item I<--cc> I<cc>, I<-C> I<cc> + +=back + + +=over + +Other users to CC on the new task. + +=back + + +=over + +=item I<--project> I<project> + +=back + + +=over + +Projects to assign to the task. + +=back + + + +B<unit> [I<options>] [I<paths>] + +B<unit> [I<options>] --rev [I<rev>] + +=over + +Supports: git, svn, hg +Run unit tests that cover specified paths. If no paths are specified, +unit tests covering all modified files will be run. + + +=over + +=item I<--coverage> + +=back + + +=over + +Always enable coverage information. + +=back + + +=over + +=item I<--detailed-coverage> + +=back + + +=over + +Show a detailed coverage report on the CLI. Implies --coverage. + +=back + + +=over + +=item I<--engine> I<classname> + +=back + + +=over + +Override configured unit engine for this project. + +=back + + +=over + +=item I<--everything> + +=back + + +=over + +Run every test. + +=back + + +=over + +=item I<--json> + +=back + + +=over + +Report results in JSON format. + +=back + + +=over + +=item I<--no-coverage> + +=back + + +=over + +Always disable coverage information. + +=back + + +=over + +=item I<--output> I<format> + +=back + + +=over + +With 'full', show full pretty report (Default). With 'json', +report results in JSON format. With 'ugly', use uglier (but +more efficient) JSON formatting. With 'none', don't print +results. + +=back + + +=over + +=item I<--rev> I<revision> + +=back + + +=over + +Supports: git, hg +Run unit tests covering changes since a specific revision. + +=back + + +=over + +=item I<--target> I<phid> + +=back + + (PROTOTYPE) Record a copy of the test results on the specified + +=over + +Harbormaster build target. + +=back + + +=over + +=item I<--ugly> + +=back + + +=over + +With --json, use uglier (but more efficient) formatting. + +=back + + +=back + +B<upgrade> + +=over + +Supports: cli +Upgrade arcanist and libphutil to the latest versions. + + +=back + +B<upload> I<file> [I<file> ...] [--json] + +=over + +Supports: filesystems +Upload a file from local disk. + + +=over + +=item I<--json> + +=back + + +=over + +Output upload information in JSON format. + +=back + + +=over + +=item I<--temporary> + +=back + + +=over + +Mark the file as temporary. Temporary files will be deleted +automatically after 24 hours. + +=back + + +=back + +B<version> [I<options>] + +=over + +Supports: cli +Shows the current version of arcanist. + + +=back + +B<which> [options] (svn) + +B<which> [options] [I<commit>] (hg, git) + +=over + +Supports: svn, git, hg +Shows which repository the current working copy corresponds to, +which commits 'arc diff' will select, and which revision is in +the working copy (or which revisions, if more than one matches). + + +=over + +=item I<--any-status> + +=back + + +=over + +Show committed and abandoned revisions. + +=back + + +=over + +=item I<--base> I<rules> + +=back + + +=over + +Supports: git, hg +Additional rules for determining base revision. + +=back + + +=over + +=item I<--head> I<commit> + +=back + + +=over + +Supports: git +Specify the end of the commit range to select. + +=back + + +=over + +=item I<--show-base> + +=back + + +=over + +Supports: git, hg +Print base commit only and exit. + +=back + + +=back + +=head1 OPTION REFERENCE + + + +=over + +=item I<--trace> + +=back + +Debugging command. Shows underlying commands as they are executed, +and full stack traces when exceptions are thrown. + + +=over + +=item I<--no-ansi> + +=back + +Output in plain ASCII text only, without color or style. + + +=over + +=item I<--ansi> + +=back + +Use formatting even in environments which probably don't support it. +Example: arc --ansi unit | less -r + + +=over + +=item I<--load-phutil-library=/path/to/library> + +=back + +Ignore libraries listed in .arcconfig and explicitly load specified +libraries instead. Mostly useful for Arcanist development. + + +=over + +=item I<--conduit-uri> I<uri> + +=back + +Ignore configured Conduit URI and use an explicit one instead. Mostly +useful for Arcanist development. + + +=over + +=item I<--conduit-token> I<token> + +=back + +Ignore configured credentials and use an explicit API token instead. + + +=over + +=item I<--conduit-version> I<version> + +=back + +Ignore software version and claim to be running some other version +instead. Mostly useful for Arcanist development. May cause bad things +to happen. + + +=over + +=item I<--conduit-timeout> I<timeout> + +=back + +Override the default Conduit timeout. Specified in seconds. + + +=over + +=item I<--config> I<key=value> + +=back + +Specify a runtime configuration value. This will take precedence +over static values, and only affect the current arcanist invocation. + + +=over + +=item I<--skip-arcconfig> + +=back + +Skip the working copy configuration file + + +=over + +=item I<--arcrc-file> I<filename> + +=back + +Use provided file instead of ~/.arcrc. diff -Nru phabricator-0~git20200925/debian/get-orig-source phabricator-0~git20220903/debian/get-orig-source --- phabricator-0~git20200925/debian/get-orig-source 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/get-orig-source 2022-09-08 13:05:07.000000000 +0000 @@ -0,0 +1,111 @@ +#!/bin/sh + +set -eu + +arcanist_repo='https://github.com/phacility/arcanist.git' +libphutil_repo='https://github.com/phacility/libphutil.git' +phabricator_repo='https://github.com/phacility/phabricator.git' + +if [ -z "${1:-}" ]; then + echo "Usage: $(basename "$0") <version>" + exit 1 +fi + +version="$1" + +if echo "$version" | grep -q '[a-z][0-9]\{8\}$'; then + version_ymd="$( + echo "$version" | + sed -E 's:^.*([0-9]{4})([0-9]{2})([0-9]{2})$:\1/\2/\3:' + )" +else + echo "E: Invalid version number: $version" + exit 1 +fi + +udate="$(date --rfc-3339=seconds --date="$version_ymd")" + +echo '# Downloading ...' + +# Clone to repo at $1 (as of $udate) to $2 +download() { + local url dest + url="$1" + dest="$2" + + mkdir -p "$(dirname "$dest")" + git clone "$url" "$dest" + ( + cd "$dest" + git checkout "$(git log -n1 --format=%h --before="$udate")" + ) +} + +download "$arcanist_repo" "arcanist-$version" +download "$libphutil_repo" "libphutil-$version" +download "$phabricator_repo" "phabricator-$version/phabricator" + +echo '# Copying git revision number...' +( + cd "phabricator-$version/phabricator" + echo "based on git revision $(git log -n1 --format=%H)." >conf/local/VERSION +) + +echo '# Cleaning up ...' +rm -r -v "arcanist-$version/src/parser/xhpast/bin/xhpast.exe" +rm -r -v "arcanist-$version/bin/arc.bat" +mv \ + "arcanist-$version/support/shell/hooks/bash-completion.sh" \ + "arcanist-$version/support/shell/hooks/arcanist.bash-completion" +chmod -x "arcanist-$version/support/unit/sleep.php" + +( + cd "phabricator-$version/phabricator/" + rm -r -v \ + externals/wordlist \ + webroot/rsrc/externals/font/fontawesome \ + webroot/rsrc/externals/d3 +) + +# Remove anything with .git* in $1, print the author time of the last +# commit (in seconds since the epoch). +clean_and_print_at() { + local dir + dir="$1" + ( + cd "$dir" + at="$(git log -n1 --format=%at)" + find . -maxdepth 1 -name '.git*' -print0 | xargs -r0 rm -rf + echo "$at" + ) +} + +arcanist_at="$(clean_and_print_at "arcanist-$version")" +libphutil_at="$(clean_and_print_at "libphutil-$version")" +phabricator_at="$(clean_and_print_at "phabricator-$version/phabricator")" + +echo '# Packing...' + +# Create a reproducible tarball $1 from $2, mtime set to $3. +# Then delete "$dir" +pack() { + local file dir mtime + file="$1" + dir="$2" + mtime="$3" + + XZ_OPT='-6v' fakeroot tar \ + --sort=name \ + --mtime="@$mtime" \ + -caf "$file" "$dir" + rm -rf "$dir" +} + +pack "phabricator_$version.orig.tar.xz" "phabricator-$version" \ + "$phabricator_at" + +pack "phabricator_$version.orig-arcanist.tar.xz" "arcanist-$version" \ + "$arcanist_at" + +pack "phabricator_$version.orig-libphutil.tar.xz" "libphutil-$version" \ + "$libphutil_at" diff -Nru phabricator-0~git20200925/debian/patches/LANG.diff phabricator-0~git20220903/debian/patches/LANG.diff --- phabricator-0~git20200925/debian/patches/LANG.diff 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/LANG.diff 2022-09-08 09:46:51.000000000 +0000 @@ -1,8 +1,6 @@ -Index: phabricator-0~git20170812/arcanist/src/repository/api/ArcanistSubversionAPI.php -=================================================================== ---- phabricator-0~git20170812.orig/arcanist/src/repository/api/ArcanistSubversionAPI.php -+++ phabricator-0~git20170812/arcanist/src/repository/api/ArcanistSubversionAPI.php -@@ -40,6 +40,7 @@ final class ArcanistSubversionAPI extend +--- a/arcanist/src/repository/api/ArcanistSubversionAPI.php ++++ b/arcanist/src/repository/api/ArcanistSubversionAPI.php +@@ -40,6 +40,7 @@ $argv[0] = 'svn '.$argv[0]; $future = newv('ExecFuture', $argv); diff -Nru phabricator-0~git20200925/debian/patches/phabricator/install.add-progress-notice.patch phabricator-0~git20220903/debian/patches/phabricator/install.add-progress-notice.patch --- phabricator-0~git20200925/debian/patches/phabricator/install.add-progress-notice.patch 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/phabricator/install.add-progress-notice.patch 2022-09-08 09:46:51.000000000 +0000 @@ -0,0 +1,19 @@ +Description: Enhance notice printed during initialisation +Author: Christoph Biedl <debian.axhn@manchmal.in-ulm.de> +Forwarded: no +Last-Update: 2021-01-15 + + This initialisation might take some time, so make user stay + patient. + +--- a/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php ++++ b/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php +@@ -983,7 +983,7 @@ + echo tsprintf( + "%s\n", + pht( +- 'Loading quickstart template onto "%s"...', ++ 'Loading quickstart template onto "%s" (may take minutes)...', + $ref_key)); + + $root = dirname(phutil_get_library_root('phabricator')); diff -Nru phabricator-0~git20200925/debian/patches/phabricator/olasd/0001-Show-repository-on-list-of-Differential-revisions.patch phabricator-0~git20220903/debian/patches/phabricator/olasd/0001-Show-repository-on-list-of-Differential-revisions.patch --- phabricator-0~git20200925/debian/patches/phabricator/olasd/0001-Show-repository-on-list-of-Differential-revisions.patch 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/phabricator/olasd/0001-Show-repository-on-list-of-Differential-revisions.patch 2022-09-05 19:23:39.000000000 +0000 @@ -0,0 +1,40 @@ +From 56d4f9d31b293090734cff311a633349ba66b0bc Mon Sep 17 00:00:00 2001 +From: Nicolas Dandrimont <olasd@softwareheritage.org> +Date: Mon, 1 Oct 2018 19:36:53 +0000 +Subject: [PATCH 1/3] Show repository on list of Differential revisions + +--- + .../view/DifferentialRevisionListView.php | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/phabricator/src/applications/differential/view/DifferentialRevisionListView.php ++++ b/phabricator/src/applications/differential/view/DifferentialRevisionListView.php +@@ -86,6 +86,10 @@ + + $author_phid = $revision->getAuthorPHID(); + $handle_phids[$author_phid] = $author_phid; ++ $repo_phid = $revision->getRepositoryPHID(); ++ if ($repo_phid) { ++ $handle_phids[$repo_phid] = $repo_phid; ++ } + } + + $handles = $viewer->loadHandles($handle_phids); +@@ -168,6 +172,17 @@ + $item->addAttribute(phutil_tag('em', array(), pht('No Reviewers'))); + } + ++ $repo_phid = $revision->getRepositoryPHID(); ++ if ($repo_phid) { ++ $item->addAttribute( ++ array( ++ pht('Repository:'), ++ ' ', ++ $handles[$repo_phid]->renderLink(), ++ ) ++ ); ++ } ++ + $item->setEpoch($revision->getDateModified()); + + if ($revision->isClosed()) { diff -Nru phabricator-0~git20200925/debian/patches/phabricator/olasd/0002-Add-some-environment-variables-when-running-git-rece.patch phabricator-0~git20220903/debian/patches/phabricator/olasd/0002-Add-some-environment-variables-when-running-git-rece.patch --- phabricator-0~git20200925/debian/patches/phabricator/olasd/0002-Add-some-environment-variables-when-running-git-rece.patch 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/phabricator/olasd/0002-Add-some-environment-variables-when-running-git-rece.patch 2022-09-05 19:23:39.000000000 +0000 @@ -0,0 +1,53 @@ +From b3a5c8da92452d4a300576981a0625646651b81c Mon Sep 17 00:00:00 2001 +From: Nicolas Dandrimont <olasd@softwareheritage.org> +Date: Sat, 24 Nov 2018 14:53:27 +0100 +Subject: [PATCH 2/3] Add some environment variables when running + git-receive-pack + +--- + .../DiffusionGitReceivePackSSHWorkflow.php | 34 +++++++++++++++++++ + 1 file changed, 34 insertions(+) + +--- a/phabricator/src/applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php ++++ b/phabricator/src/applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php +@@ -89,6 +89,40 @@ + return $err; + } + ++ public function getEnvironment() { ++ $env = parent::getEnvironment(); ++ ++ $repository = $this->getRepository(); ++ foreach($repository->toDictionary() as $key => $value) { ++ if(is_string($value)) { ++ $env['PHABRICATOR_REPO_' . strtoupper($key)] = $value; ++ } ++ } ++ ++ $io_readwrite = PhabricatorRepositoryURI::IO_READWRITE; ++ $protocol_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH; ++ ++ $uris = $repository->getURIs(); ++ foreach ($uris as $uri) { ++ if ($uri->getIsDisabled()) { ++ continue; ++ } ++ ++ if ($uri->getDefaultIOType() != $io_readwrite) { ++ continue; ++ } ++ ++ if ($uri->getBuiltinProtocol() != $protocol_ssh) { ++ continue; ++ } ++ ++ $env['PHABRICATOR_REPO_PUSH_URI'] = (string)$uri->getDisplayURI(); ++ break; ++ } ++ ++ return $env; ++ } ++ + private function executeRepositoryCommand($command) { + $repository = $this->getRepository(); + $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); diff -Nru phabricator-0~git20200925/debian/patches/phabricator/olasd/0003-Add-a-parser-for-a-custom-Related-to-keyword-in-the-.patch phabricator-0~git20220903/debian/patches/phabricator/olasd/0003-Add-a-parser-for-a-custom-Related-to-keyword-in-the-.patch --- phabricator-0~git20200925/debian/patches/phabricator/olasd/0003-Add-a-parser-for-a-custom-Related-to-keyword-in-the-.patch 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/phabricator/olasd/0003-Add-a-parser-for-a-custom-Related-to-keyword-in-the-.patch 2022-09-08 09:46:51.000000000 +0000 @@ -0,0 +1,85 @@ +From c194cd353b3673dc63d11b0767cec84850b7f806 Mon Sep 17 00:00:00 2001 +From: Nicolas Dandrimont <olasd@softwareheritage.org> +Date: Tue, 14 Apr 2020 10:57:08 +0200 +Subject: [PATCH 3/3] Add a parser for a custom "Related to" keyword in the + body of Diffs + +This allows us to link between tasks and diffs automatically, without changing +the status of tasks. +--- + src/__phutil_library_map__.php | 2 ++ + .../editor/DifferentialTransactionEditor.php | 9 ++++++ + ...DifferentialCustomFieldRelatedToParser.php | 31 +++++++++++++++++++ + 3 files changed, 42 insertions(+) + create mode 100644 src/applications/differential/parser/DifferentialCustomFieldRelatedToParser.php + +--- a/phabricator/src/__phutil_library_map__.php ++++ b/phabricator/src/__phutil_library_map__.php +@@ -513,6 +513,7 @@ + 'DifferentialCustomFieldDependsOnParser' => 'applications/differential/parser/DifferentialCustomFieldDependsOnParser.php', + 'DifferentialCustomFieldDependsOnParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCustomFieldDependsOnParserTestCase.php', + 'DifferentialCustomFieldNumericIndex' => 'applications/differential/storage/DifferentialCustomFieldNumericIndex.php', ++ 'DifferentialCustomFieldRelatedToParser' => 'applications/differential/parser/DifferentialCustomFieldRelatedToParser.php', + 'DifferentialCustomFieldRevertsParser' => 'applications/differential/parser/DifferentialCustomFieldRevertsParser.php', + 'DifferentialCustomFieldRevertsParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCustomFieldRevertsParserTestCase.php', + 'DifferentialCustomFieldStorage' => 'applications/differential/storage/DifferentialCustomFieldStorage.php', +@@ -6512,6 +6513,7 @@ + 'DifferentialCustomFieldDependsOnParser' => 'PhabricatorCustomFieldMonogramParser', + 'DifferentialCustomFieldDependsOnParserTestCase' => 'PhabricatorTestCase', + 'DifferentialCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', ++ 'DifferentialCustomFieldRelatedToParser' => 'PhabricatorCustomFieldMonogramParser', + 'DifferentialCustomFieldRevertsParser' => 'PhabricatorCustomFieldMonogramParser', + 'DifferentialCustomFieldRevertsParserTestCase' => 'PhabricatorTestCase', + 'DifferentialCustomFieldStorage' => 'PhabricatorCustomFieldStorage', +--- a/phabricator/src/applications/differential/editor/DifferentialTransactionEditor.php ++++ b/phabricator/src/applications/differential/editor/DifferentialTransactionEditor.php +@@ -834,6 +834,15 @@ + } + } + ++ $related_refs = id(new DifferentialCustomFieldRelatedToParser()) ++ ->parseCorpus($content_block); ++ foreach ($related_refs as $match) { ++ foreach ($match['monograms'] as $monogram) { ++ $task_id = (int)trim($monogram, 'tT'); ++ $task_map[$task_id] = true; ++ } ++ } ++ + $rev_map = array(); + $rev_refs = id(new DifferentialCustomFieldDependsOnParser()) + ->parseCorpus($content_block); +--- /dev/null ++++ b/phabricator/src/applications/differential/parser/DifferentialCustomFieldRelatedToParser.php +@@ -0,0 +1,31 @@ ++<?php ++ ++final class DifferentialCustomFieldRelatedToParser ++ extends PhabricatorCustomFieldMonogramParser { ++ ++ protected function getPrefixes() { ++ return array( ++ 'related to', ++ ); ++ } ++ ++ protected function getInfixes() { ++ return array( ++ 'task', ++ 'tasks', ++ 'issue', ++ 'issues', ++ 'bug', ++ 'bugs', ++ ); ++ } ++ ++ protected function getSuffixes() { ++ return array(); ++ } ++ ++ protected function getMonogramPattern() { ++ return '[Tt]\d+'; ++ } ++ ++} diff -Nru phabricator-0~git20200925/debian/patches/puppet-lint-line.diff phabricator-0~git20220903/debian/patches/puppet-lint-line.diff --- phabricator-0~git20200925/debian/patches/puppet-lint-line.diff 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/puppet-lint-line.diff 2022-09-08 09:46:51.000000000 +0000 @@ -1,11 +1,9 @@ This removes the deprecated %{linenumber} from puppet-lint according to https://github.com/rodjek/puppet-lint/issues/539. Debian bugreport #878157. -Index: phabricator-0~git20170812/arcanist/src/lint/linter/ArcanistPuppetLintLinter.php -=================================================================== ---- phabricator-0~git20170812.orig/arcanist/src/lint/linter/ArcanistPuppetLintLinter.php -+++ phabricator-0~git20170812/arcanist/src/lint/linter/ArcanistPuppetLintLinter.php -@@ -56,7 +56,7 @@ final class ArcanistPuppetLintLinter ext +--- a/arcanist/src/lint/linter/ArcanistPuppetLintLinter.php ++++ b/arcanist/src/lint/linter/ArcanistPuppetLintLinter.php +@@ -56,7 +56,7 @@ return array( '--error-level=all', sprintf('--log-format=%s', implode('|', array( diff -Nru phabricator-0~git20200925/debian/patches/series phabricator-0~git20220903/debian/patches/series --- phabricator-0~git20200925/debian/patches/series 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/series 2022-10-07 17:59:57.000000000 +0000 @@ -1,3 +1,10 @@ update-references-to-php5.patch LANG.diff puppet-lint-line.diff +support-arcanist-invocation.patch + +phabricator/olasd/0001-Show-repository-on-list-of-Differential-revisions.patch +phabricator/olasd/0002-Add-some-environment-variables-when-running-git-rece.patch +phabricator/olasd/0003-Add-a-parser-for-a-custom-Related-to-keyword-in-the-.patch + +phabricator/install.add-progress-notice.patch diff -Nru phabricator-0~git20200925/debian/patches/support-arcanist-invocation.patch phabricator-0~git20220903/debian/patches/support-arcanist-invocation.patch --- phabricator-0~git20200925/debian/patches/support-arcanist-invocation.patch 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/support-arcanist-invocation.patch 2022-10-07 18:05:38.000000000 +0000 @@ -0,0 +1,22 @@ +Description: Support invocation as "arcanist" +Author: Christoph Biedl <debian.axhn@manchmal.in-ulm.de> +Bug-Debian: https://bugs.debian.org/1020840 +Forwarded: not-needed +Last-Update: 2022-10-07 + + Followup to #919697: The arc program must not be installed at + /usr/bin/arc, but using /usr/bin/arcanist triggers an error from the + program as it doesn't know anything about this. + +--- a/arcanist/src/runtime/ArcanistRuntime.php ++++ b/arcanist/src/runtime/ArcanistRuntime.php +@@ -514,6 +514,9 @@ + + private function newToolset(array $argv) { + $binary = basename($argv[0]); ++ if ($binary == 'arcanist') { ++ $binary = 'arc'; ++ } + + $toolsets = ArcanistToolset::newToolsetMap(); + if (!isset($toolsets[$binary])) { diff -Nru phabricator-0~git20200925/debian/patches/update-references-to-php5.patch phabricator-0~git20220903/debian/patches/update-references-to-php5.patch --- phabricator-0~git20200925/debian/patches/update-references-to-php5.patch 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/patches/update-references-to-php5.patch 2022-09-08 09:46:51.000000000 +0000 @@ -2,11 +2,9 @@ Author: Nishanth Aravamudan <nish.aravamudan@canonical.com> Bug-Ubuntu: https://launchpad.net/bugs/1544352 -Index: phabricator-0~git20180509/arcanist/scripts/arcanist.php -=================================================================== ---- phabricator-0~git20180509.orig/arcanist/scripts/arcanist.php -+++ phabricator-0~git20180509/arcanist/scripts/arcanist.php -@@ -471,9 +471,8 @@ function sanity_check_environment() { +--- a/arcanist/scripts/arcanist.php ++++ b/arcanist/scripts/arcanist.php +@@ -504,9 +504,8 @@ $need_functions = array( 'curl_init' => array( 'text', @@ -18,11 +16,9 @@ ), 'json_decode' => array('flag', '--without-json'), ); -Index: phabricator-0~git20180509/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php -=================================================================== ---- phabricator-0~git20180509.orig/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php -+++ phabricator-0~git20180509/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php -@@ -261,7 +261,7 @@ final class PhabricatorLDAPAuthProvider +--- a/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php ++++ b/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php +@@ -264,7 +264,7 @@ 'talk to LDAP. Usually you can install it with '. '`%s`, `%s`, or a similar package manager command.', 'yum install php-ldap', @@ -31,11 +27,9 @@ } } -Index: phabricator-0~git20180509/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php -=================================================================== ---- phabricator-0~git20180509.orig/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php -+++ phabricator-0~git20180509/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php -@@ -73,20 +73,16 @@ final class PhabricatorSetupIssueView ex +--- a/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php ++++ b/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php +@@ -73,20 +73,16 @@ 'Install these %d PHP extension(s):', count($extensions)); $install_info = pht( @@ -61,24 +55,9 @@ $fallback_info = pht( "If those commands don't work, try Google. The process of installing ". -Index: phabricator-0~git20180509/phabricator/src/applications/phragment/storage/PhragmentFragment.php -=================================================================== ---- phabricator-0~git20180509.orig/phabricator/src/applications/phragment/storage/PhragmentFragment.php -+++ phabricator-0~git20180509/phabricator/src/applications/phragment/storage/PhragmentFragment.php -@@ -155,7 +155,7 @@ final class PhragmentFragment extends Ph - try { - $zip = new ZipArchive(); - } catch (Exception $e) { -- // The server doesn't have php5-zip, so we can't do recursive updates. -+ // The server doesn't have php-zip, so we can't do recursive updates. - return; - } - -Index: phabricator-0~git20180509/phabricator/src/docs/user/configuration/configuration_guide.diviner -=================================================================== ---- phabricator-0~git20180509.orig/phabricator/src/docs/user/configuration/configuration_guide.diviner -+++ phabricator-0~git20180509/phabricator/src/docs/user/configuration/configuration_guide.diviner -@@ -138,7 +138,7 @@ server.modules list: +--- a/phabricator/src/docs/user/configuration/configuration_guide.diviner ++++ b/phabricator/src/docs/user/configuration/configuration_guide.diviner +@@ -138,7 +138,7 @@ Finally, you should run the following commands to enable php support: @@ -87,35 +66,29 @@ $ sudo lighty-enable-mod fastcgi-php Restart lighttpd after making your edits, then continue below. -Index: phabricator-0~git20180509/phabricator/src/docs/user/field/restarting.diviner -=================================================================== ---- phabricator-0~git20180509.orig/phabricator/src/docs/user/field/restarting.diviner -+++ phabricator-0~git20180509/phabricator/src/docs/user/field/restarting.diviner -@@ -112,5 +112,5 @@ like one of these on your system, or a d +--- a/phabricator/src/docs/user/field/restarting.diviner ++++ b/phabricator/src/docs/user/field/restarting.diviner +@@ -112,5 +112,5 @@ ``` $ sudo /etc/init.d/php-fpm restart -$ sudo service php5-fpm reload +$ sudo service php-fpm reload ``` -Index: phabricator-0~git20180509/phabricator/src/docs/user/installation_guide.diviner -=================================================================== ---- phabricator-0~git20180509.orig/phabricator/src/docs/user/installation_guide.diviner -+++ phabricator-0~git20180509/phabricator/src/docs/user/installation_guide.diviner -@@ -123,7 +123,7 @@ Otherwise, here's a general description +--- a/phabricator/src/docs/user/installation_guide.diviner ++++ b/phabricator/src/docs/user/installation_guide.diviner +@@ -109,7 +109,7 @@ - MySQL Server (usually "mysqld" or "mysql-server") - PHP (usually "php") - Required PHP extensions: mbstring, iconv, mysql (or mysqli), curl, pcntl - (these might be something like "php-mysql" or "php5-mysqlnd") + (these might be something like "php-mysql" or "php-mysqlnd") - - Optional PHP extensions: gd, apc (special instructions for APC are available - below if you have difficulty installing it), xhprof (instructions below, - you only need this if you are developing Phabricator) -Index: phabricator-0~git20180509/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php -=================================================================== ---- phabricator-0~git20180509.orig/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php -+++ phabricator-0~git20180509/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php -@@ -83,7 +83,7 @@ final class PhabricatorPHPConfigSetupChe + - Optional PHP extensions: gd + + If you already have LAMP setup, you've probably already got everything you need. +--- a/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php ++++ b/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php +@@ -83,7 +83,7 @@ // NOTE: We're intentionally telling you to install "mysqlnd" here; on // Ubuntu, there's no separate "mysqli" package. @@ -124,7 +97,7 @@ $this->newIssue('php.mysqli') ->setName(pht('MySQLi Extension Not Available')) -@@ -103,7 +103,7 @@ final class PhabricatorPHPConfigSetupChe +@@ -103,7 +103,7 @@ 'native driver is recommended.'. "\n\n". 'You may be able to install the native driver with a command like: %s', diff -Nru phabricator-0~git20200925/debian/phabricator.nginx.conf phabricator-0~git20220903/debian/phabricator.nginx.conf --- phabricator-0~git20200925/debian/phabricator.nginx.conf 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/phabricator.nginx.conf 2022-09-08 16:48:13.000000000 +0000 @@ -12,7 +12,7 @@ } location /index.php { - fastcgi_pass unix:/run/php-fpm.sock; + fastcgi_pass unix:/run/php/php7.4-fpm.sock; fastcgi_index index.php; #required if PHP was built with --enable-force-cgi-redirect diff -Nru phabricator-0~git20200925/debian/phabricator.postinst phabricator-0~git20220903/debian/phabricator.postinst --- phabricator-0~git20200925/debian/phabricator.postinst 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/phabricator.postinst 2022-09-08 16:48:13.000000000 +0000 @@ -34,11 +34,11 @@ for dir in $repo_default_local_path $log_directory; do #create a statoverride unless one already exists if ! dpkg-statoverride --list $dir >/dev/null 2>&1; then - dpkg-statoverride --update --add phabricator nogroup 755 $dir + dpkg-statoverride --update --add phabricator nogroup 755 $dir fi done -touch $local_conf_file +[ -f "$local_conf_file" ] || echo '{}' >"$local_conf_file" set_config() { #we check if the configuration option is already set or not, in order to avoid overwritting local modifications @@ -55,11 +55,13 @@ #see http://us3.php.net/date_default_timezone_get set_config phabricator.timezone $(cat /etc/timezone) -set_config phd.pid-directory "/run/phabricator" #repository.default-local-path is where phabricator daemon will set up repositories set_config repository.default-local-path $repo_default_local_path set_config phd.log-directory $log_directory +#be polite by default +set_config phabricator.serious-business true + if [[ -n $phabricator_mysql_user && -n $phabricator_mysql_pwd ]]; then /usr/share/phabricator/bin/config set mysql.host $mysql_host /usr/share/phabricator/bin/config set mysql.user $phabricator_mysql_user @@ -72,7 +74,7 @@ # echo "Not finished. please reconfigure" if ! dpkg-statoverride --list $local_conf_file >/dev/null 2>&1; then - dpkg-statoverride --update --add root www-data 640 $local_conf_file + dpkg-statoverride --update --add root www-data 640 $local_conf_file fi ### Webserver configuration @@ -84,6 +86,115 @@ ucf --debconf-ok /usr/share/phabricator/conf_templates/phabricator.nginx.conf /etc/nginx/sites-available/phabricator.conf ucfr phabricator /etc/nginx/sites-available/phabricator.conf + +### PHP configuration + +TEMPDIR="$(mktemp --directory --tmpdir "phabricator.postinst.$$.XXXXX")" +trap "cd / ; rm -rf \"$TEMPDIR\"" EXIT + +TEMP_PHP_INI="$TEMPDIR/php.ini" + +# Set a value in an ini file, the key might be commented out, though +# $1: The ini file +# $2: The section +# $3: The key +# $4: The desired value +# $5: If set: Value is a number with "M" appended, desired value must +# be this or higher +edit_ini () { + local FILE ; FILE="$1" + local SECTION ; SECTION="$2" + local PARAMETER ; PARAMETER="$3" + local VALUE ; VALUE="$4" + local MEGS ; MEGS="${5:-}" + + CURRENT="$(crudini --get "$FILE" "$SECTION" "$PARAMETER" 2>/dev/null || :)" + + TEMP2="$TEMP_PHP_INI.1" + + if [ -z "$CURRENT" ] ; then + # not set, perhaps commented out? + N="$(grep -n "^; *$PARAMETER *=" "$FILE" | cut -d: -f1)" + if [ "$N" ] ; then + # okay, uncomment + cp "$FILE" "$TEMP2" + sed -i -e "$N,${N}s/^; *//" "$FILE" + CURRENT="$(crudini --get "$FILE" "$SECTION" "$PARAMETER" 2>/dev/null || :)" + if [ -z "$CURRENT" ] ; then + # seldom: That didn't work, revert + cp "$TEMP2" "$FILE" + fi + fi + fi + + if [ "$CURRENT" ] ; then + if [ "$MEGS" ] ; then + # compare current value + if \ + echo "$CURRENT" | grep -iq '^[0-9][0-9]*m$' && + [ "$(echo "$CURRENT" | sed -e 's/ *[mM]//')" -ge "$(echo "$VALUE" | sed -e 's/ *[mM]//')" ] + then + # good enough + return + fi + elif [ "$CURRENT" = "$VALUE" ] ; then + # value already set + return + fi + fi + + # set + crudini --set "$FILE" "$SECTION" "$PARAMETER" "$VALUE" +} + + +for PHP_INI in /etc/php/*/apache2/php.ini ; do + [ -f "$PHP_INI" ] || continue + + cp "$PHP_INI" "$TEMP_PHP_INI" + + # Have a bigger post_max_size, at least 32M + edit_ini "$TEMP_PHP_INI" 'PHP' 'post_max_size' '32M' 1 + + # Configure opcache for production + edit_ini "$TEMP_PHP_INI" 'opcache' 'opcache.validate_timestamps' '0' + + + ucf --debconf-ok "$TEMP_PHP_INI" "$PHP_INI" + # purge but don't fail if it doesn't belong to us + ucfr --purge "$PHP_INI" 2>/dev/null || : + + # TODO: Restart apache2 upon changes + # (not sure, config continues below) +done + +# mariadb configuration +# Only if dbhost = localhost + +TEMP_SERVER_CNF="$TEMPDIR/50-server.cnf" + +for SERVER_CNF in /etc/mysql/mariadb.conf.d/50-server.cnf ; do + [ -f "$SERVER_CNF" ] || continue + + cp "$SERVER_CNF" "$TEMP_SERVER_CNF" + + edit_ini "$TEMP_SERVER_CNF" 'mysqld' 'max_allowed_packet' '32M' 1 + + # not at all sure about that + edit_ini "$TEMP_SERVER_CNF" 'mysqld' 'sql_mode' 'STRICT_ALL_TABLES' + + edit_ini "$TEMP_SERVER_CNF" 'mysqld' 'innodb_buffer_pool_size' '1600M' 1 + + edit_ini "$TEMP_SERVER_CNF" 'mysqld' 'local_infile' '0' + + ucf --debconf-ok "$TEMP_SERVER_CNF" "$SERVER_CNF" + # purge but don't fail if it doesn't belong to us + ucfr --purge "$SERVER_CNF" 2>/dev/null || : + + # TODO: Restart mariadb upon changes +done + + db_stop # Update the webserver, if needed diff -Nru phabricator-0~git20200925/debian/phabricator.README.Debian phabricator-0~git20220903/debian/phabricator.README.Debian --- phabricator-0~git20200925/debian/phabricator.README.Debian 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/debian/phabricator.README.Debian 2022-09-05 19:23:39.000000000 +0000 @@ -0,0 +1,106 @@ +Security warning +================ + +After initial installation, phabricator will grant full access to the +first person who connects to it. So do not, repeat: DO NOT make the web +server world-wide accessible until after some configuration. + + +First installation +================== + +The "Loading quickstart template" operation takes some time. Please +be patient. + +This package provides only a very basic installation. Many steps are +still left to you. + +Initial configuration might be a bit unusual: First you create an +account, possibly named "admin", then you add an "auth provider" (see +below), finally use "Password" in the settings page to trigger a +password reset. + + +Strongly recommended +-------------------- + +* Mail configuration + +If you have a local mailserver (exim, postfix, nullmailer - anything +that provides /usr/sbin/sendmail), add the following lines to +`/var/lib/phabricator/local.json` + + "cluster.mailers": [ + { + "key": "default-sendmail", + "type": "sendmail" + } + ] + +Where the text in "key" is not important. And make sure this file +is still valid JSON. + +* "Auth provider" + +See "Auth" in the left tab on the main page. In case of doubt, +"Username/Password" is the way to go. + +Afterwards, lock the auth config as suggested by phabricator. + + +Recommended +----------- + +* pygment support + +You have to install both python3-pygments and python3-pkg-resources. +Then, as usual, in local.conf set "pygments.enabled" to true (without +quotes). + +* Other + +There are several "Setup Issues" behind the yellow exclamation mark. +Follow wisely. + + +Gotchas +======= + +Don't be tempted to use an address `...@localhost` for the initial +account creation. This address is accepted but sending a password +recovery e-mail to that address will fail. + +php8 is not (yet) supported. + +Help needed! +============ + +phabricator is a huge and complex software, and the Debian package is +certainly far from being perfect. Please let us know if you see room +for improvement. + + + -- Christoph Biedl <debian.axhn@manchmal.in-ulm.de> Tue, 26 Jan 2021 17:43:29 +0100 + + +Older README +============ + +(might be outdated) + + +phabricator for Debian +----------------- +* According to phabricator developers, everything in phabricator/externals is external code highly customized for phabricator. It cannot be packaged otherwise. For an example of what was modified and links for further details, see the lintian override for php mailer. +* __tests__ directories are packaged on purpose. Do not remove them if you don't want your phabricator instance to FATAL at runtime +* if you are affected by bug 720434 (http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=720434), daemons won't be able to start properly. This is unfortunate but has nothing to do with phabricator. Get the correct php.ini (cp /usr/share/php/php.ini-production.cli /etc/php/cli/php.ini) and the daemons will work as expected. +* Debian does not allow us to ship the most used passwords list compiled by openwall, so phabricator won't be able to tell you if your password is vulnerable to bruteforce. The openwall list is 3500+ passwords long, but only 634 are 8+ chars long (the minimum password length with phabricator default settings) and only one (winniethepooh) is 12+ chars long. So ensure your users use a long enough password and you won't miss this file. + +Diffusion repository hosting +----------------- +Phabricator allows you to host repositories and serve them by http/ssh. This unfortunately cannot be done automagically by the phabricator package, so you will need to follow the instructions available at https://secure.phabricator.com/book/phabricator/article/diffusion_hosting/. Please note the daemon-user referred in the documentation is created by this package and is called phabricator. The webserver user is created by your webserver and is usually called www-data. + + -- Sylvestre Ledru <sylvestre@debian.org>, Sat, 12 Aug 2017 20:22:39 +0200 + + + diff -Nru phabricator-0~git20200925/debian/README.Debian phabricator-0~git20220903/debian/README.Debian --- phabricator-0~git20200925/debian/README.Debian 2018-05-13 16:23:48.000000000 +0000 +++ phabricator-0~git20220903/debian/README.Debian 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -phabricator for Debian ------------------ -* According to phabricator developers, everything in phabricator/externals is external code highly customized for phabricator. It cannot be packaged otherwise. For an example of what was modified and links for further details, see the lintian override for php mailer. -* __tests__ directories are packaged on purpose. Do not remove them if you don't want your phabricator instance to FATAL at runtime -* if you are affected by bug 720434 (http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=720434), daemons won't be able to start properly. This is unfortunate but has nothing to do with phabricator. Get the correct php.ini (cp /usr/share/php/php.ini-production.cli /etc/php/cli/php.ini) and the daemons will work as expected. -* Debian does not allow us to ship the most used passwords list compiled by openwall, so phabricator won't be able to tell you if your password is vulnerable to bruteforce. The openwall list is 3500+ passwords long, but only 634 are 8+ chars long (the minimum password length with phabricator default settings) and only one (winniethepooh) is 12+ chars long. So ensure your users use a long enough password and you won't miss this file. -* phabricator needs the php mailparse extension for inbound emails with local MTA. Unfortunately this is not (yet?) packaged for debian due to licensing reasons. See #754977 (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=754977) for more infos. Please use "sudo pecl install mailparse" if you need to install it. - -Diffusion repository hosting ------------------ -Phabricator allows you to host repositories and serve them by http/ssh. This unfortunately cannot be done automagically by the phabricator package, so you will need to follow the instructions available at https://secure.phabricator.com/book/phabricator/article/diffusion_hosting/. Please note the daemon-user referred in the documentation is created by this package and is called phabricator. The webserver user is created by your webserver and is usually called www-data. - - -- Sylvestre Ledru <sylvestre@debian.org>, Sat, 12 Aug 2017 20:22:39 +0200 diff -Nru phabricator-0~git20200925/debian/rules phabricator-0~git20220903/debian/rules --- phabricator-0~git20200925/debian/rules 2020-09-25 07:59:46.000000000 +0000 +++ phabricator-0~git20220903/debian/rules 2022-09-08 13:05:07.000000000 +0000 @@ -7,7 +7,7 @@ PKD = $(abspath $(dir $(MAKEFILE_LIST))) PKG = "phabricator" -UVER = $(shell dpkg-parsechangelog -l$(PKD)/changelog | perl -ne 'print $$1 if m{^Version:\s+(?:\d+:)?(\d.*)(?:\-\d+.*)};') +UVER = $(shell dpkg-parsechangelog -l$(PKD)/changelog -SVersion | sed -E -e 's/-[0-9]+//') DTYPE = VER ?= $(subst $(DTYPE),,$(UVER)) @@ -18,46 +18,17 @@ debconf-updatepo dh_clean -ARCANIST = git://github.com/phacility/arcanist.git -LIBPHUTIL = git://github.com/phacility/libphutil.git -PHABRICATOR = git://github.com/phacility/phabricator.git UDATE = $(shell date --rfc-3339=seconds --date='TZ="UTC" $(shell echo $(VER) | perl -ne 'print "$$1-$$2-$$3" if m/\+(?:git|svn|hg)(\d{4})(\d{2})(\d{2})/')') get-orig-source: $(info I: UDATE=$(UDATE)) $(if $(wildcard $(PKG)-$(VER)),$(error $(PKG)-$(VER) exist, aborting..)) - @echo "# Downloading..." - mkdir -p phabricator-$(VER)/ - git clone $(ARCANIST) arcanist-$(VER) - git clone $(LIBPHUTIL) libphutil-$(VER) - git clone $(PHABRICATOR) phabricator-$(VER)/phabricator - for P in arcanist-$(VER) libphutil-$(VER) phabricator-$(VER)/phabricator; do \ - cd $$P && git checkout $$(git log -n1 --format=%h --before="$(UDATE)") && cd -; \ - done - echo "# Copying git revision number..." - cd phabricator-$(VER); echo "based on git revision $$(git log -n1 --format=%H)." > phabricator/conf/local/VERSION; cd .. - echo "# Cleaning-up..." - $(RM) -r -v arcanist-$(VER)/src/parser/xhpast/bin/xhpast.exe - $(RM) -r -v arcanist-$(VER)/bin/arc.bat - @mv arcanist-$(VER)/support/shell/hooks/bash-completion.sh arcanist-$(VER)/support/shell/hooks/arcanist.bash-completion - chmod -x arcanist-$(VER)/support/unit/sleep.php - cd phabricator-$(VER)/phabricator/ && \ - $(RM) -r -v externals/twilio-php/docs \ - externals/wordlist \ - webroot/rsrc/externals/font/fontawesome \ - webroot/rsrc/externals/font/sourcesans \ - webroot/rsrc/externals/d3 - $(RM) -r arcanist-$(VER)/.git* libphutil-$(VER)/.git* phabricator-$(VER)/phabricator/.git* - @echo "# Packing..." - XZ_OPT="-6v" tar -caf phabricator_$(VER).orig.tar.xz phabricator-$(VER) - XZ_OPT="-6v" tar -caf phabricator_$(VER).orig-arcanist.tar.xz arcanist-$(VER) - XZ_OPT="-6v" tar -caf phabricator_$(VER).orig-libphutil.tar.xz libphutil-$(VER) - rm -rf phabricator-$(VER) arcanist-$(VER) libphutil-$(VER) + debian/get-orig-source $(VER) -generate-manpage: debian/arc.1 +generate-manpage: debian/doc/arc.1 -debian/arc.pod: debian/arc.cat1 +debian/doc/arc.pod: debian/doc/arc.cat1 debian/cat2pod < $< > $@ -debian/arc.1: debian/arc.pod +debian/doc/arc.1: debian/doc/arc.pod pod2man -r "" -c "User Commands" $< $@ .PHONY: override_dh_clean get-orig-source generate-manpage diff -Nru phabricator-0~git20200925/phabricator/.arclint phabricator-0~git20220903/phabricator/.arclint --- phabricator-0~git20200925/phabricator/.arclint 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/.arclint 2022-06-14 16:29:55.000000000 +0000 @@ -79,7 +79,8 @@ "xhpast": { "type": "xhpast", "include": "(\\.php$)", - "standard": "phutil.xhpast" + "standard": "phutil.xhpast", + "xhpast.php-version": "5.5" } } } diff -Nru phabricator-0~git20200925/phabricator/bin/celerity phabricator-0~git20220903/phabricator/bin/celerity --- phabricator-0~git20200925/phabricator/bin/celerity 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/bin/celerity 2022-06-14 16:29:55.000000000 +0000 @@ -2,7 +2,7 @@ <?php $root = dirname(dirname(dirname(__FILE__))); -require_once $root.'/scripts/__init_script__.php'; +require_once $root.'/scripts/init/init-setup.php'; $args = new PhutilArgumentParser($argv); $args->setTagline(pht('manage celerity')); diff -Nru phabricator-0~git20200925/phabricator/bin/commit-hook phabricator-0~git20220903/phabricator/bin/commit-hook --- phabricator-0~git20200925/phabricator/bin/commit-hook 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/bin/commit-hook 2022-06-14 16:29:55.000000000 +0000 @@ -122,9 +122,9 @@ if (!strlen($username)) { throw new Exception( pht( - 'No Direct Pushes: You are pushing directly to a repository hosted '. - 'by Phabricator. This will not work. See "No Direct Pushes" in the '. - 'documentation for more information.')); + 'No Direct Pushes: You are pushing directly to a hosted repository. '. + 'This will not work. See "No Direct Pushes" in the documentation '. + 'for more information.')); } if ($repository->isHg()) { diff -Nru phabricator-0~git20200925/phabricator/bin/ssh-auth phabricator-0~git20220903/phabricator/bin/ssh-auth --- phabricator-0~git20200925/phabricator/bin/ssh-auth 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/bin/ssh-auth 2022-06-14 16:29:55.000000000 +0000 @@ -4,6 +4,11 @@ $root = dirname(dirname(dirname(__FILE__))); require_once $root.'/scripts/init/init-script.php'; +$error_log = id(new PhutilErrorLog()) + ->setLogName(pht('SSH Error Log')) + ->setLogPath(PhabricatorEnv::getEnvConfig('log.ssh-error.path')) + ->activateLog(); + // TODO: For now, this is using "parseParital()", not "parse()". This allows // the script to accept (and ignore) additional arguments. This preserves // backward compatibility until installs have time to migrate to the new diff -Nru phabricator-0~git20200925/phabricator/bin/ssh-connect phabricator-0~git20220903/phabricator/bin/ssh-connect --- phabricator-0~git20200925/phabricator/bin/ssh-connect 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/bin/ssh-connect 2022-06-14 16:29:55.000000000 +0000 @@ -154,6 +154,6 @@ array_unshift($arguments, $pattern); $err = newv('PhutilExecPassthru', $arguments) - ->execute(); + ->resolve(); exit($err); diff -Nru phabricator-0~git20200925/phabricator/bin/ssh-exec phabricator-0~git20220903/phabricator/bin/ssh-exec --- phabricator-0~git20200925/phabricator/bin/ssh-exec 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/bin/ssh-exec 2022-06-14 16:29:55.000000000 +0000 @@ -4,7 +4,12 @@ $ssh_start_time = microtime(true); $root = dirname(dirname(dirname(__FILE__))); -require_once $root.'/scripts/__init_script__.php'; +require_once $root.'/scripts/init/init-script.php'; + +$error_log = id(new PhutilErrorLog()) + ->setLogName(pht('SSH Error Log')) + ->setLogPath(PhabricatorEnv::getEnvConfig('log.ssh-error.path')) + ->activateLog(); $ssh_log = PhabricatorSSHLog::getLog(); @@ -125,9 +130,9 @@ if (!PhabricatorEnv::isClusterAddress($remote_address)) { throw new Exception( pht( - 'This request originates from outside of the Phabricator cluster '. - 'address range. Requests signed with a trusted device key must '. - 'originate from trusted hosts.')); + 'This request originates from outside of the cluster address range. '. + 'Requests signed with a trusted device key must originate from '. + 'trusted hosts.')); } $device = id(new AlmanacDeviceQuery()) @@ -141,6 +146,14 @@ $device_name)); } + if ($device->isDisabled()) { + throw new Exception( + pht( + 'This request has authenticated as a device ("%s"), but this '. + 'device is disabled.', + $device->getName())); + } + // We're authenticated as a device, but we're going to read the user out of // the command below. $is_cluster_request = true; @@ -215,7 +228,9 @@ $command_list = implode(', ', $command_list); $error_lines = array(); - $error_lines[] = pht('Welcome to Phabricator.'); + $error_lines[] = pht( + 'Welcome to %s.', + PlatformSymbols::getPlatformServerName()); $error_lines[] = pht( 'You are logged in as %s.', $user_name); @@ -223,7 +238,7 @@ if (!$original_argv) { $error_lines[] = pht( 'You have not specified a command to run. This means you are requesting '. - 'an interactive shell, but Phabricator does not provide interactive '. + 'an interactive shell, but this server does not provide interactive '. 'shells over SSH.'); $error_lines[] = pht( '(Usually, you should run a command like "git clone" or "hg push" '. @@ -257,7 +272,7 @@ if (empty($workflows[$command])) { $error_lines[] = pht( 'You have specified the command "%s", but that command is not '. - 'supported by Phabricator. As received by Phabricator, your entire '. + 'supported by this server. As received by this server, your entire '. 'argument list was:', $command); diff -Nru phabricator-0~git20200925/phabricator/bin/storage phabricator-0~git20220903/phabricator/bin/storage --- phabricator-0~git20200925/phabricator/bin/storage 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/bin/storage 2022-06-14 16:29:55.000000000 +0000 @@ -5,13 +5,13 @@ require_once $root.'/scripts/init/init-setup.php'; $args = new PhutilArgumentParser($argv); -$args->setTagline(pht('manage Phabricator storage and schemata')); +$args->setTagline(pht('manage storage and schemata')); $args->setSynopsis(<<<EOHELP **storage** __workflow__ [__options__] -Manage Phabricator database storage and schema versioning. +Manage database storage and schema versioning. **storage** upgrade -Initialize or upgrade Phabricator storage. +Initialize or upgrade storage. **storage** upgrade --user __root__ --password __hunter2__ Use administrative credentials for schema changes. @@ -74,7 +74,7 @@ 'name' => 'disable-utf8mb4', 'help' => pht( 'Disable %s, even if the database supports it. This is an '. - 'advanced feature used for testing changes to Phabricator; you '. + 'advanced feature used for testing internal changes; you '. 'should not normally use this flag.', 'utf8mb4'), ), @@ -95,7 +95,7 @@ $host = $args->getArg('host'); $ref_key = $args->getArg('ref'); -if (strlen($host) || strlen($ref_key)) { +if (($host !== null) || ($ref_key !== null)) { if ($host && $ref_key) { throw new PhutilArgumentUsageException( pht( @@ -168,9 +168,9 @@ 'Unable to connect to MySQL using the configured credentials. '. 'You must configure standard credentials before you can upgrade '. 'storage. Run these commands to set up credentials:'), - " phabricator/ $ ./bin/config set mysql.host __host__\n". - " phabricator/ $ ./bin/config set mysql.user __username__\n". - " phabricator/ $ ./bin/config set mysql.pass __password__", + " $ ./bin/config set mysql.host __host__\n". + " $ ./bin/config set mysql.user __username__\n". + " $ ./bin/config set mysql.pass __password__", pht( 'These standard credentials are separate from any administrative '. 'credentials provided to this command with __%s__ or '. diff -Nru phabricator-0~git20200925/phabricator/conf/local/VERSION phabricator-0~git20220903/phabricator/conf/local/VERSION --- phabricator-0~git20200925/phabricator/conf/local/VERSION 2020-09-25 09:12:07.000000000 +0000 +++ phabricator-0~git20220903/phabricator/conf/local/VERSION 2022-06-14 16:29:55.000000000 +0000 @@ -1 +1 @@ -based on git revision 9dcad56c25dd25a544b1d52c677cb5581e3864e3. +based on git revision 9426765a2c6a149f5b0ed2d9132cd1e4e7ee152d. diff -Nru phabricator-0~git20200925/phabricator/externals/diff_match_patch/diff_match_patch.php phabricator-0~git20220903/phabricator/externals/diff_match_patch/diff_match_patch.php --- phabricator-0~git20200925/phabricator/externals/diff_match_patch/diff_match_patch.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/externals/diff_match_patch/diff_match_patch.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,2117 +0,0 @@ -<?php -/** - * Diff Match and Patch - * - * Copyright 2006 Google Inc. - * http://code.google.com/p/google-diff-match-patch/ - * - * php port by Tobias Buschor shwups.ch - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Computes the difference between two texts to create a patch. - * Applies the patch onto another text, allowing for errors. - * @author fraser@google.com (Neil Fraser) - */ - -/** - * Class containing the diff, match and patch methods. - * @constructor - */ -class diff_match_patch { - - // Defaults. - // Redefine these in your program to override the defaults. - - // Number of seconds to map a diff before giving up (0 for infinity). - public $Diff_Timeout = 1.0; - // Cost of an empty edit operation in terms of edit characters. - public $Diff_EditCost = 4; - // The size beyond which the double-ended diff activates. - // Double-ending is twice as fast, but less accurate. - public $Diff_DualThreshold = 32; - // At what point is no match declared (0.0 = perfection, 1.0 = very loose). - public $Match_Threshold = 0.5; - // How far to search for a match (0 = exact location, 1000+ = broad match). - // A match this many characters away from the expected location will add - // 1.0 to the score (0.0 is a perfect match). - public $Match_Distance = 1000; - // When deleting a large block of text (over ~64 characters), how close does - // the contents have to match the expected contents. (0.0 = perfection, - // 1.0 = very loose). Note that Match_Threshold controls how closely the - // end points of a delete need to match. - public $Patch_DeleteThreshold = 0.5; - // Chunk size for context length. - public $Patch_Margin = 4; - - /** - * Compute the number of bits in an int. - * The normal answer for JavaScript is 32. - * @return {number} Max bits - - function getMaxBits() { - var maxbits = 0; - var oldi = 1; - var newi = 2; - while (oldi != newi) { - maxbits++; - oldi = newi; - newi = newi << 1; - } - return maxbits; - } - // How many bits in a number? - this.Match_MaxBits = getMaxBits(); - */ - // DIFF FUNCTIONS - - /** - * Find the differences between two texts. Simplifies the problem by stripping - * any common prefix or suffix off the texts before diffing. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @param {boolean} opt_checklines Optional speedup flag. If present and false, - * then don't run a line-level diff first to identify the changed areas. - * Defaults to true, which does a faster, slightly less optimal diff - * @return {Array.<Array.<number|string>>} Array of diff tuples. - */ - function diff_main($text1, $text2, $checklines = true) { - // Check for equality (speedup) - if ($text1 === $text2) { - return array ( array ( DIFF_EQUAL, $text1) ); - } - - // Trim off common prefix (speedup) - $commonlength = $this->diff_commonPrefix($text1, $text2); - $commonprefix = mb_substr($text1, 0, $commonlength); - $text1 = mb_substr($text1, $commonlength); - $text2 = mb_substr($text2, $commonlength); - - // Trim off common suffix (speedup) - $commonlength = $this->diff_commonSuffix($text1, $text2); - $commonsuffix = mb_substr($text1, mb_strlen($text1) - $commonlength); - $text1 = mb_substr($text1, 0, mb_strlen($text1) - $commonlength); - $text2 = mb_substr($text2, 0, mb_strlen($text2) - $commonlength); - - // Compute the diff on the middle block - $diffs = $this->diff_compute($text1, $text2, $checklines); - - // Restore the prefix and suffix - if ($commonprefix !== '') { - array_unshift($diffs, array ( DIFF_EQUAL, $commonprefix )); - } - if ($commonsuffix !== '') { - array_push($diffs, array ( DIFF_EQUAL, $commonsuffix )); - } - $this->diff_cleanupMerge($diffs); - return $diffs; - } - - /** - * Find the differences between two texts. Assumes that the texts do not - * have any common prefix or suffix. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @param {boolean} checklines Speedup flag. If false, then don't run a - * line-level diff first to identify the changed areas. - * If true, then run a faster, slightly less optimal diff - * @return {Array.<Array.<number|string>>} Array of diff tuples. - * @private - */ - function diff_compute($text1, $text2, $checklines) { - - if ($text1 === '') { - // Just add some text (speedup) - return array ( array ( DIFF_INSERT, $text2 ) ); - } - - if ($text2 === '') { - // Just delete some text (speedup) - return array ( array ( DIFF_DELETE, $text1 ) ); - } - - $longtext = mb_strlen($text1) > mb_strlen($text2) ? $text1 : $text2; - $shorttext = mb_strlen($text1) > mb_strlen($text2) ? $text2 : $text1; - $i = mb_strpos($longtext, $shorttext); - if ($i !== false) { - // Shorter text is inside the longer text (speedup) - $diffs = array ( - array ( DIFF_INSERT, mb_substr($longtext, 0, $i) ), - array ( DIFF_EQUAL, $shorttext ), - array ( DIFF_INSERT, mb_substr($longtext, $i +mb_strlen($shorttext)) ) - ); - - // Swap insertions for deletions if diff is reversed. - if (mb_strlen($text1) > mb_strlen($text2)) { - $diffs[0][0] = $diffs[2][0] = DIFF_DELETE; - } - return $diffs; - } - $longtext = $shorttext = null; // Garbage collect - - // Check to see if the problem can be split in two. - $hm = $this->diff_halfMatch($text1, $text2); - if ($hm) { - // A half-match was found, sort out the return data. - $text1_a = $hm[0]; - $text1_b = $hm[1]; - $text2_a = $hm[2]; - $text2_b = $hm[3]; - $mid_common = $hm[4]; - // Send both pairs off for separate processing. - $diffs_a = $this->diff_main($text1_a, $text2_a, $checklines); - $diffs_b = $this->diff_main($text1_b, $text2_b, $checklines); - // Merge the results. - return array_merge($diffs_a, array ( - array ( - DIFF_EQUAL, - $mid_common - ) - ), $diffs_b); - } - - // Perform a real diff. - if ($checklines && (mb_strlen($text1) < 100 || mb_strlen($text2) < 100)) { - // Too trivial for the overhead. - $checklines = false; - } - $linearray = null; - if ($checklines) { - // Scan the text on a line-by-line basis first. - $a = $this->diff_linesToChars($text1, $text2); - $text1 = $a[0]; - $text2 = $a[1]; - $linearray = $a[2]; - } - $diffs = $this->diff_map($text1, $text2); - if (!$diffs) { - // No acceptable result. - $diffs = array ( - array ( - DIFF_DELETE, - $text1 - ), - array ( - DIFF_INSERT, - $text2 - ) - ); - } - if ($checklines) { - // Convert the diff back to original text. - $this->diff_charsToLines($diffs, $linearray); - // Eliminate freak matches (e.g. blank lines) - $this->diff_cleanupSemantic($diffs); - - // Rediff any replacement blocks, this time character-by-character. - // Add a dummy entry at the end. - array_push($diffs, array ( - DIFF_EQUAL, - '' - )); - $pointer = 0; - $count_delete = 0; - $count_insert = 0; - $text_delete = ''; - $text_insert = ''; - while ($pointer < count($diffs)) { - switch ($diffs[$pointer][0]) { - case DIFF_INSERT : - $count_insert++; - $text_insert .= $diffs[$pointer][1]; - break; - case DIFF_DELETE : - $count_delete++; - $text_delete .= $diffs[$pointer][1]; - break; - case DIFF_EQUAL : - // Upon reaching an equality, check for prior redundancies. - if ($count_delete >= 1 && $count_insert >= 1) { - // Delete the offending records and add the merged ones. - $a = $this->diff_main($text_delete, $text_insert, false); - array_splice($diffs, $pointer - $count_delete - $count_insert, $count_delete + $count_insert); - - $pointer = $pointer - $count_delete - $count_insert; - for ($j = count($a) - 1; $j >= 0; $j--) { - array_splice($diffs, $pointer, 0, array($a[$j])); - } - $pointer = $pointer +count($a); - } - $count_insert = 0; - $count_delete = 0; - $text_delete = ''; - $text_insert = ''; - break; - } - $pointer++; - } - array_pop($diffs); // Remove the dummy entry at the end. - } - return $diffs; - } - - /** - * Split two texts into an array of strings. Reduce the texts to a string of - * hashes where each Unicode character represents one line. - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {Array.<string|Array.<string>>} Three element Array, containing the - * encoded text1, the encoded text2 and the array of unique strings. The - * zeroth element of the array of unique strings is intentionally blank. - * @private - */ - function diff_linesToChars($text1, $text2) { - $lineArray = array(); // e.g. lineArray[4] == 'Hello\n' - $lineHash = array(); // e.g. lineHash['Hello\n'] == 4 - - // '\x00' is a valid character, but various debuggers don't like it. - // So we'll insert a junk entry to avoid generating a null character. - $lineArray[0] = ''; - - $chars1 = $this->diff_linesToCharsMunge($text1, $lineArray, $lineHash); - $chars2 = $this->diff_linesToCharsMunge($text2, $lineArray, $lineHash); - return array ( - $chars1, - $chars2, - $lineArray - ); - } - - /** - * Split a text into an array of strings. Reduce the texts to a string of - * hashes where each Unicode character represents one line. - * Modifies linearray and linehash through being a closure. - * @param {string} text String to encode - * @return {string} Encoded string - * @private - */ - function diff_linesToCharsMunge($text, &$lineArray, &$lineHash) { - $chars = ''; - // Walk the text, pulling out a mb_substring for each line. - // text.split('\n') would would temporarily double our memory footprint. - // Modifying text would create many large strings to garbage collect. - $lineStart = 0; - $lineEnd = -1; - // Keeping our own length variable is faster than looking it up. - $lineArrayLength = count($lineArray); - while ($lineEnd < mb_strlen($text) - 1) { - $lineEnd = mb_strpos($text, "\n", $lineStart); - if ($lineEnd === false) { - $lineEnd = mb_strlen($text) - 1; - } - $line = mb_substr($text, $lineStart, $lineEnd +1 -$lineStart); - $lineStart = $lineEnd +1; - - if ( isset($lineHash[$line]) ) { - $chars .= mb_chr($lineHash[$line]); - } else { - $chars .= mb_chr($lineArrayLength); - $lineHash[$line] = $lineArrayLength; - $lineArray[$lineArrayLength++] = $line; - } - } - return $chars; - } - /** - * Rehydrate the text in a diff from a string of line hashes to real lines of - * text. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - * @param {Array.<string>} lineArray Array of unique strings. - * @private - */ - function diff_charsToLines(&$diffs, $lineArray) { - for ($x = 0; $x < count($diffs); $x++) { - $chars = $diffs[$x][1]; - $text = array (); - for ($y = 0; $y < mb_strlen($chars); $y++) { - $text[$y] = $lineArray[charCodeAt($chars, $y)]; - } - $diffs[$x][1] = implode('',$text); - } - } - - /** - * Explore the intersection points between the two texts. - * @param {string} text1 Old string to be diffed. - * @param {string} text2 New string to be diffed. - * @return {Array.<Array.<number|string>>?} Array of diff tuples or null if no - * diff available. - * @private - */ - function diff_map($text1, $text2) { - // Don't run for too long. - $ms_end = microtime(true) + $this->Diff_Timeout; - - // Cache the text lengths to prevent multiple calls. - $text1_length = mb_strlen($text1); - $text2_length = mb_strlen($text2); - $max_d = $text1_length + $text2_length -1; - $doubleEnd = $this->Diff_DualThreshold * 2 < $max_d; - $v_map1 = array(); - $v_map2 = array(); - $v1 = array(); - $v2 = array(); - $v1[1] = 0; - $v2[1] = 0; - $x = null; - $y = null; - $footstep = null; // Used to track overlapping paths. - $footsteps = array(); - $done = false; - // Safari 1.x doesn't have hasOwnProperty - //? $hasOwnProperty = !!(footsteps.hasOwnProperty); - // If the total number of characters is odd, then the front path will collide - // with the reverse path. - $front = ($text1_length + $text2_length) % 2; - for ($d = 0; $d < $max_d; $d++) { - // Bail out if timeout reached. - if ($this->Diff_Timeout > 0 && microtime(true) > $ms_end) { - return null; // zzz - } - - // Walk the front path one step. - $v_map1[$d] = array (); - for ($k = -$d; $k <= $d; $k += 2) { - if ($k == -$d || $k != $d && $v1[$k -1] < $v1[$k +1]) { - $x = $v1[$k +1]; - } else { - $x = $v1[$k -1] + 1; - } - $y = $x - $k; - if ($doubleEnd) { - $footstep = $x . ',' . $y; - if ($front && isset ($footsteps[$footstep])) { - $done = true; - } - if (!$front) { - $footsteps[$footstep] = $d; - } - } - while (!$done && ($x < $text1_length) && ($y < $text2_length) && (mb_substr($text1, $x, 1) == mb_substr($text2, $y, 1)) ) { - $x++; - $y++; - if ($doubleEnd) { - $footstep = $x . ',' . $y; - if ($front && isset ($footsteps[$footstep])) { - $done = true; - } - if (!$front) { - $footsteps[$footstep] = $d; - } - } - } - $v1[$k] = $x; - $v_map1[$d][$x . ',' . $y] = true; - if ($x == $text1_length && $y == $text2_length) { - // Reached the end in single-path mode. - return $this->diff_path1($v_map1, $text1, $text2); - } - elseif ($done) { - // Front path ran over reverse path. - - $v_map2 = array_slice($v_map2, 0, $footsteps[$footstep] + 1); - $a = $this->diff_path1($v_map1, mb_substr($text1, 0, $x), mb_substr($text2, 0, $y)); - - return array_merge($a, $this->diff_path2($v_map2, mb_substr($text1, $x), mb_substr($text2, $y))); - } - } - - if ($doubleEnd) { - // Walk the reverse path one step. - $v_map2[$d] = array(); - for ($k = -$d; $k <= $d; $k += 2) { - if ($k == -$d || $k != $d && $v2[$k -1] < $v2[$k +1]) { - $x = $v2[$k +1]; - } else { - $x = $v2[$k -1] + 1; - } - $y = $x - $k; - $footstep = ($text1_length - $x) . ',' . ($text2_length - $y); - if (!$front && isset ($footsteps[$footstep])) { - $done = true; - } - if ($front) { - $footsteps[$footstep] = $d; - } - while (!$done && $x < $text1_length && $y < $text2_length && mb_substr($text1, $text1_length - $x -1, 1) == mb_substr($text2, $text2_length - $y -1, 1) ) { - $x++; - $y++; - $footstep = ($text1_length - $x) . ',' . ($text2_length - $y); - if (!$front && isset ($footsteps[$footstep])) { - $done = true; - } - if ($front) { - $footsteps[$footstep] = $d; - } - } - $v2[$k] = $x; - $v_map2[$d][$x . ',' . $y] = true; - if ($done) { - // Reverse path ran over front path. - $v_map1 = array_slice($v_map1, 0, $footsteps[$footstep] + 1); - $a = $this->diff_path1($v_map1, mb_substr($text1, 0, $text1_length - $x), mb_substr($text2, 0, $text2_length - $y)); - return array_merge($a, $this->diff_path2($v_map2, mb_substr($text1, $text1_length - $x), mb_substr($text2, $text2_length - $y))); - } - } - } - } - // Number of diffs equals number of characters, no commonality at all. - return null; - } - - /** - * Work from the middle back to the start to determine the path. - * @param {Array.<Object>} v_map Array of paths.ers - * @param {string} text1 Old string fragment to be diffed. - * @param {string} text2 New string fragment to be diffed. - * @return {Array.<Array.<number|string>>} Array of diff tuples. - * @private - */ - function diff_path1($v_map, $text1, $text2) { - $path = array (); - $x = mb_strlen($text1); - $y = mb_strlen($text2); - /** @type {number?} */ - $last_op = null; - for ($d = count($v_map) - 2; $d >= 0; $d--) { - while (1) { - if (isset ($v_map[$d][($x -1) . ',' . $y])) { - $x--; - if ($last_op === DIFF_DELETE) { - $path[0][1] = mb_substr($text1, $x, 1) . $path[0][1]; - } else { - array_unshift($path, array ( - DIFF_DELETE, - mb_substr($text1, $x, 1) - )); - } - $last_op = DIFF_DELETE; - break; - } elseif (isset ($v_map[$d][$x . ',' . ($y -1)])) { - $y--; - if ($last_op === DIFF_INSERT) { - $path[0][1] = mb_substr($text2, $y, 1) . $path[0][1]; - } else { - array_unshift($path, array ( - DIFF_INSERT, - mb_substr($text2, $y, 1) - )); - } - $last_op = DIFF_INSERT; - break; - } else { - $x--; - $y--; - //if (text1.charAt(x) != text2.charAt(y)) { - // throw new Error('No diagonal. Can\'t happen. (diff_path1)'); - //} - if ($last_op === DIFF_EQUAL) { - $path[0][1] = mb_substr($text1, $x, 1) . $path[0][1]; - } else { - array_unshift($path, array ( - DIFF_EQUAL, - mb_substr($text1, $x, 1) - )); - } - $last_op = DIFF_EQUAL; - } - } - } - return $path; - } - - /** - * Work from the middle back to the end to determine the path. - * @param {Array.<Object>} v_map Array of paths. - * @param {string} text1 Old string fragment to be diffed. - * @param {string} text2 New string fragment to be diffed. - * @return {Array.<Array.<number|string>>} Array of diff tuples. - * @private - */ - function diff_path2($v_map, $text1, $text2) { - $path = array (); - $pathLength = 0; - $x = mb_strlen($text1); - $y = mb_strlen($text2); - /** @type {number?} */ - $last_op = null; - for ($d = count($v_map) - 2; $d >= 0; $d--) { - while (1) { - if (isset ($v_map[$d][($x -1) . ',' . $y])) { - $x--; - if ($last_op === DIFF_DELETE) { - $path[$pathLength -1][1] .= $text1[mb_strlen($text1) - $x -1]; - } else { - $path[$pathLength++] = array ( - DIFF_DELETE, - $text1[mb_strlen($text1) - $x -1] - ); - } - $last_op = DIFF_DELETE; - break; - } - elseif (isset ($v_map[$d][$x . ',' . ($y -1)])) { - $y--; - if ($last_op === DIFF_INSERT) { - $path[$pathLength -1][1] .= $text2[mb_strlen($text2) - $y -1]; - } else { - $path[$pathLength++] = array ( - DIFF_INSERT, - $text2[mb_strlen($text2) - $y -1] - ); - } - $last_op = DIFF_INSERT; - break; - } else { - $x--; - $y--; - //if (text1.charAt(text1.length - x - 1) != - // text2.charAt(text2.length - y - 1)) { - // throw new Error('No diagonal. Can\'t happen. (diff_path2)'); - //} - if ($last_op === DIFF_EQUAL) { - $path[$pathLength -1][1] .= $text1[mb_strlen($text1) - $x -1]; - } else { - $path[$pathLength++] = array ( - DIFF_EQUAL, - $text1[mb_strlen($text1) - $x -1] - ); - } - $last_op = DIFF_EQUAL; - } - } - } - return $path; - } - - /** - * Determine the common prefix of two strings - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {number} The number of characters common to the start of each - * string. - */ - function diff_commonPrefix($text1, $text2) { - for ($i = 0; 1; $i++) { - $t1 = mb_substr($text1, $i, 1); - $t2 = mb_substr($text2, $i, 1); - if($t1==='' || $t2==='' || $t1 !== $t2 ){ - return $i; - } - } - } - - /** - * Determine the common suffix of two strings - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {number} The number of characters common to the end of each string. - */ - function diff_commonSuffix($text1, $text2) { - return $this->diff_commonPrefix( strrev($text1), strrev($text2) ); - } - - /** - * Do the two texts share a mb_substring which is at least half the length of the - * longer text? - * @param {string} text1 First string. - * @param {string} text2 Second string. - * @return {Array.<string>?} Five element Array, containing the prefix of - * text1, the suffix of text1, the prefix of text2, the suffix of - * text2 and the common middle. Or null if there was no match. - */ - function diff_halfMatch($text1, $text2) { - $longtext = mb_strlen($text1) > mb_strlen($text2) ? $text1 : $text2; - $shorttext = mb_strlen($text1) > mb_strlen($text2) ? $text2 : $text1; - if (mb_strlen($longtext) < 10 || mb_strlen($shorttext) < 1) { - return null; // Pointless. - } - - // First check if the second quarter is the seed for a half-match. - $hm1 = $this->diff_halfMatchI($longtext, $shorttext, ceil(mb_strlen($longtext) / 4)); - // Check again based on the third quarter. - $hm2 = $this->diff_halfMatchI($longtext, $shorttext, ceil(mb_strlen($longtext) / 2)); - - if (!$hm1 && !$hm2) { - return null; - } elseif (!$hm2) { - $hm = $hm1; - } elseif (!$hm1) { - $hm = $hm2; - } else { - // Both matched. Select the longest. - $hm = mb_strlen($hm1[4]) > mb_strlen($hm2[4]) ? $hm1 : $hm2; - } - - // A half-match was found, sort out the return data. - if (mb_strlen($text1) > mb_strlen($text2)) { - $text1_a = $hm[0]; - $text1_b = $hm[1]; - $text2_a = $hm[2]; - $text2_b = $hm[3]; - } else { - $text2_a = $hm[0]; - $text2_b = $hm[1]; - $text1_a = $hm[2]; - $text1_b = $hm[3]; - } - $mid_common = $hm[4]; - return array( $text1_a, $text1_b, $text2_a, $text2_b, $mid_common ); - } - - /** - * Does a mb_substring of shorttext exist within longtext such that the mb_substring - * is at least half the length of longtext? - * Closure, but does not reference any external variables. - * @param {string} longtext Longer string. - * @param {string} shorttext Shorter string. - * @param {number} i Start index of quarter length mb_substring within longtext - * @return {Array.<string>?} Five element Array, containing the prefix of - * longtext, the suffix of longtext, the prefix of shorttext, the suffix - * of shorttext and the common middle. Or null if there was no match. - * @private - */ - function diff_halfMatchI($longtext, $shorttext, $i) { - // Start with a 1/4 length mb_substring at position i as a seed. - $seed = mb_substr($longtext, $i, floor(mb_strlen($longtext) / 4)); - - $j = -1; - $best_common = ''; - $best_longtext_a = null; - $best_longtext_b = null; - $best_shorttext_a = null; - $best_shorttext_b = null; - while ( ($j = mb_strpos($shorttext, $seed, $j + 1)) !== false ) { - $prefixLength = $this->diff_commonPrefix(mb_substr($longtext, $i), mb_substr($shorttext, $j)); - $suffixLength = $this->diff_commonSuffix(mb_substr($longtext, 0, $i), mb_substr($shorttext, 0, $j)); - if (mb_strlen($best_common) < $suffixLength + $prefixLength) { - $best_common = mb_substr($shorttext, $j - $suffixLength, $suffixLength) . mb_substr($shorttext, $j, $prefixLength); - $best_longtext_a = mb_substr($longtext, 0, $i - $suffixLength); - $best_longtext_b = mb_substr($longtext, $i + $prefixLength); - $best_shorttext_a = mb_substr($shorttext, 0, $j - $suffixLength); - $best_shorttext_b = mb_substr($shorttext, $j + $prefixLength); - } - } - if (mb_strlen($best_common) >= mb_strlen($longtext) / 2) { - return array ( - $best_longtext_a, - $best_longtext_b, - $best_shorttext_a, - $best_shorttext_b, - $best_common - ); - } else { - return null; - } - } - - /** - * Reduce the number of edits by eliminating semantically trivial equalities. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - */ - function diff_cleanupSemantic(&$diffs) { - $changes = false; - $equalities = array (); // Stack of indices where equalities are found. - $equalitiesLength = 0; // Keeping our own length var is faster in JS. - $lastequality = null; // Always equal to equalities[equalitiesLength-1][1] - $pointer = 0; // Index of current position. - // Number of characters that changed prior to the equality. - $length_changes1 = 0; - // Number of characters that changed after the equality. - $length_changes2 = 0; - while ($pointer < count($diffs)) { - if ($diffs[$pointer][0] == DIFF_EQUAL) { // equality found - $equalities[$equalitiesLength++] = $pointer; - $length_changes1 = $length_changes2; - $length_changes2 = 0; - $lastequality = $diffs[$pointer][1]; - } else { // an insertion or deletion - $length_changes2 += mb_strlen($diffs[$pointer][1]); - if ($lastequality !== null && (mb_strlen($lastequality) <= $length_changes1) && (mb_strlen($lastequality) <= $length_changes2)) { - // Duplicate record - $zzz_diffs = array_splice($diffs, $equalities[$equalitiesLength -1], 0, array(array ( - DIFF_DELETE, - $lastequality - ))); - // Change second copy to insert. - $diffs[$equalities[$equalitiesLength -1] + 1][0] = DIFF_INSERT; - // Throw away the equality we just deleted. - $equalitiesLength--; - // Throw away the previous equality (it needs to be reevaluated). - $equalitiesLength--; - $pointer = $equalitiesLength > 0 ? $equalities[$equalitiesLength -1] : -1; - $length_changes1 = 0; // Reset the counters. - $length_changes2 = 0; - $lastequality = null; - $changes = true; - } - } - $pointer++; - } - if ($changes) { - $this->diff_cleanupMerge($diffs); - } - $this->diff_cleanupSemanticLossless($diffs); - } - - /** - * Look for single edits surrounded on both sides by equalities - * which can be shifted sideways to align the edit to a word boundary. - * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - */ - function diff_cleanupSemanticLossless(&$diffs) { - - $pointer = 1; - // Intentionally ignore the first and last element (don't need checking). - while ($pointer < count($diffs) - 1) { - if ($diffs[$pointer -1][0] == DIFF_EQUAL && $diffs[$pointer +1][0] == DIFF_EQUAL) { - // This is a single edit surrounded by equalities. - $equality1 = $diffs[$pointer -1][1]; - $edit = $diffs[$pointer][1]; - $equality2 = $diffs[$pointer +1][1]; - - // First, shift the edit as far left as possible. - $commonOffset = $this->diff_commonSuffix($equality1, $edit); - if ($commonOffset !== '') { - $commonString = mb_substr($edit, mb_strlen($edit) - $commonOffset); - $equality1 = mb_substr($equality1, 0, mb_strlen($equality1) - $commonOffset); - $edit = $commonString . mb_substr($edit, 0, mb_strlen($edit) - $commonOffset); - $equality2 = $commonString . $equality2; - } - - // Second, step character by character right, looking for the best fit. - $bestEquality1 = $equality1; - $bestEdit = $edit; - $bestEquality2 = $equality2; - $bestScore = $this->diff_cleanupSemanticScore($equality1, $edit) + $this->diff_cleanupSemanticScore($edit, $equality2); - while (isset($equality2[0]) && $edit[0] === $equality2[0]) { - $equality1 .= $edit[0]; - $edit = mb_substr($edit, 1) . $equality2[0]; - $equality2 = mb_substr($equality2, 1); - $score = $this->diff_cleanupSemanticScore($equality1, $edit) + $this->diff_cleanupSemanticScore($edit, $equality2); - // The >= encourages trailing rather than leading whitespace on edits. - if ($score >= $bestScore) { - $bestScore = $score; - $bestEquality1 = $equality1; - $bestEdit = $edit; - $bestEquality2 = $equality2; - } - } - - if ($diffs[$pointer -1][1] != $bestEquality1) { - // We have an improvement, save it back to the diff. - if ($bestEquality1) { - $diffs[$pointer -1][1] = $bestEquality1; - } else { - $zzz_diffs = array_splice($diffs, $pointer -1, 1); - $pointer--; - } - $diffs[$pointer][1] = $bestEdit; - if ($bestEquality2) { - $diffs[$pointer +1][1] = $bestEquality2; - } else { - $zzz_diffs = array_splice($diffs, $pointer +1, 1); - $pointer--; - } - } - } - $pointer++; - } - } - - /** - * Given two strings, compute a score representing whether the internal - * boundary falls on logical boundaries. - * Scores range from 5 (best) to 0 (worst). - * Closure, makes reference to regex patterns defined above. - * @param {string} one First string - * @param {string} two Second string - * @return {number} The score. - */ - function diff_cleanupSemanticScore($one, $two) { - // Define some regex patterns for matching boundaries. - $punctuation = '/[^a-zA-Z0-9]/'; - $whitespace = '/\s/'; - $linebreak = '/[\r\n]/'; - $blanklineEnd = '/\n\r?\n$/'; - $blanklineStart = '/^\r?\n\r?\n/'; - - if (!$one || !$two) { - // Edges are the best. - return 5; - } - - // Each port of this function behaves slightly differently due to - // subtle differences in each language's definition of things like - // 'whitespace'. Since this function's purpose is largely cosmetic, - // the choice has been made to use each language's native features - // rather than force total conformity. - $score = 0; - // One point for non-alphanumeric. - if (preg_match($punctuation, $one[mb_strlen($one) - 1]) || preg_match($punctuation, $two[0])) { - $score++; - // Two points for whitespace. - if (preg_match($whitespace, $one[mb_strlen($one) - 1] ) || preg_match($whitespace, $two[0])) { - $score++; - // Three points for line breaks. - if (preg_match($linebreak, $one[mb_strlen($one) - 1]) || preg_match($linebreak, $two[0])) { - $score++; - // Four points for blank lines. - if (preg_match($blanklineEnd, $one) || preg_match($blanklineStart, $two)) { - $score++; - } - } - } - } - return $score; - } - - /** - * Reduce the number of edits by eliminating operationally trivial equalities. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - */ - function diff_cleanupEfficiency(&$diffs) { - $changes = false; - $equalities = array (); // Stack of indices where equalities are found. - $equalitiesLength = 0; // Keeping our own length var is faster in JS. - $lastequality = ''; // Always equal to equalities[equalitiesLength-1][1] - $pointer = 0; // Index of current position. - // Is there an insertion operation before the last equality. - $pre_ins = false; - // Is there a deletion operation before the last equality. - $pre_del = false; - // Is there an insertion operation after the last equality. - $post_ins = false; - // Is there a deletion operation after the last equality. - $post_del = false; - while ($pointer < count($diffs)) { - if ($diffs[$pointer][0] == DIFF_EQUAL) { // equality found - if (mb_strlen($diffs[$pointer][1]) < $this->Diff_EditCost && ($post_ins || $post_del)) { - // Candidate found. - $equalities[$equalitiesLength++] = $pointer; - $pre_ins = $post_ins; - $pre_del = $post_del; - $lastequality = $diffs[$pointer][1]; - } else { - // Not a candidate, and can never become one. - $equalitiesLength = 0; - $lastequality = ''; - } - $post_ins = $post_del = false; - } else { // an insertion or deletion - if ($diffs[$pointer][0] == DIFF_DELETE) { - $post_del = true; - } else { - $post_ins = true; - } - /* - * Five types to be split: - * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del> - * <ins>A</ins>X<ins>C</ins><del>D</del> - * <ins>A</ins><del>B</del>X<ins>C</ins> - * <ins>A</del>X<ins>C</ins><del>D</del> - * <ins>A</ins><del>B</del>X<del>C</del> - */ - if ($lastequality && (($pre_ins && $pre_del && $post_ins && $post_del) || ((mb_strlen($lastequality) < $this->Diff_EditCost / 2) && ($pre_ins + $pre_del + $post_ins + $post_del) == 3))) { - // Duplicate record - $zzz_diffs = array_splice($diffs, $equalities[$equalitiesLength -1], 0, array(array ( - DIFF_DELETE, - $lastequality - ))); - // Change second copy to insert. - $diffs[$equalities[$equalitiesLength -1] + 1][0] = DIFF_INSERT; - $equalitiesLength--; // Throw away the equality we just deleted; - $lastequality = ''; - if ($pre_ins && $pre_del) { - // No changes made which could affect previous entry, keep going. - $post_ins = $post_del = true; - $equalitiesLength = 0; - } else { - $equalitiesLength--; // Throw away the previous equality; - $pointer = $equalitiesLength > 0 ? $equalities[$equalitiesLength -1] : -1; - $post_ins = $post_del = false; - } - $changes = true; - } - } - $pointer++; - } - - if ($changes) { - $this->diff_cleanupMerge($diffs); - } - } - - /** - * Reorder and merge like edit sections. Merge equalities. - * Any edit section can move as long as it doesn't cross an equality. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - */ - function diff_cleanupMerge(&$diffs) { - array_push($diffs, array ( DIFF_EQUAL, '' )); // Add a dummy entry at the end. - $pointer = 0; - $count_delete = 0; - $count_insert = 0; - $text_delete = ''; - $text_insert = ''; - $commonlength = null; - while ($pointer < count($diffs)) { - switch ($diffs[$pointer][0]) { - case DIFF_INSERT : - $count_insert++; - $text_insert .= $diffs[$pointer][1]; - $pointer++; - break; - case DIFF_DELETE : - $count_delete++; - $text_delete .= $diffs[$pointer][1]; - $pointer++; - break; - case DIFF_EQUAL : - // Upon reaching an equality, check for prior redundancies. - if ($count_delete !== 0 || $count_insert !== 0) { - if ($count_delete !== 0 && $count_insert !== 0) { - // Factor out any common prefixies. - $commonlength = $this->diff_commonPrefix($text_insert, $text_delete); - if ($commonlength !== 0) { - if (($pointer - $count_delete - $count_insert) > 0 && $diffs[$pointer - $count_delete - $count_insert -1][0] == DIFF_EQUAL) { - $diffs[$pointer - $count_delete - $count_insert -1][1] .= mb_substr($text_insert, 0, $commonlength); - } else { - array_splice($diffs, 0, 0, array(array ( - DIFF_EQUAL, - mb_substr($text_insert, 0, $commonlength) - ))); - $pointer++; - } - $text_insert = mb_substr($text_insert, $commonlength); - $text_delete = mb_substr($text_delete, $commonlength); - } - // Factor out any common suffixies. - $commonlength = $this->diff_commonSuffix($text_insert, $text_delete); - if ($commonlength !== 0) { - $diffs[$pointer][1] = mb_substr($text_insert, mb_strlen($text_insert) - $commonlength) . $diffs[$pointer][1]; - $text_insert = mb_substr($text_insert, 0, mb_strlen($text_insert) - $commonlength); - $text_delete = mb_substr($text_delete, 0, mb_strlen($text_delete) - $commonlength); - } - } - // Delete the offending records and add the merged ones. - if ($count_delete === 0) { - array_splice($diffs, $pointer-$count_delete-$count_insert, $count_delete+$count_insert, array(array( - DIFF_INSERT, - $text_insert - ))); - } elseif ($count_insert === 0) { - array_splice($diffs, $pointer-$count_delete-$count_insert, $count_delete+$count_insert, array(array( - DIFF_DELETE, - $text_delete - ))); - } else { - array_splice($diffs, $pointer-$count_delete-$count_insert, $count_delete+$count_insert, array(array( - DIFF_DELETE, - $text_delete - ), array ( - DIFF_INSERT, - $text_insert - ))); - } - $pointer = $pointer - $count_delete - $count_insert + ($count_delete ? 1 : 0) + ($count_insert ? 1 : 0) + 1; - } elseif ($pointer !== 0 && $diffs[$pointer -1][0] == DIFF_EQUAL) { - // Merge this equality with the previous one. - $diffs[$pointer -1][1] .= $diffs[$pointer][1]; - array_splice($diffs, $pointer, 1); - } else { - $pointer++; - } - $count_insert = 0; - $count_delete = 0; - $text_delete = ''; - $text_insert = ''; - break; - } - } - if ($diffs[count($diffs) - 1][1] === '') { - array_pop($diffs); // Remove the dummy entry at the end. - } - - // Second pass: look for single edits surrounded on both sides by equalities - // which can be shifted sideways to eliminate an equality. - // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC - $changes = false; - $pointer = 1; - // Intentionally ignore the first and last element (don't need checking). - while ($pointer < count($diffs) - 1) { - if ($diffs[$pointer-1][0] == DIFF_EQUAL && $diffs[$pointer+1][0] == DIFF_EQUAL) { - // This is a single edit surrounded by equalities. - if ( mb_substr($diffs[$pointer][1], mb_strlen($diffs[$pointer][1]) - mb_strlen($diffs[$pointer -1][1])) == $diffs[$pointer -1][1]) { - // Shift the edit over the previous equality. - $diffs[$pointer][1] = $diffs[$pointer -1][1] . mb_substr($diffs[$pointer][1], 0, mb_strlen($diffs[$pointer][1]) - mb_strlen($diffs[$pointer -1][1])); - $diffs[$pointer +1][1] = $diffs[$pointer -1][1] . $diffs[$pointer +1][1]; - array_splice($diffs, $pointer -1, 1); - $changes = true; - } elseif (mb_substr($diffs[$pointer][1], 0, mb_strlen($diffs[$pointer +1][1])) == $diffs[$pointer +1][1]) { - // Shift the edit over the next equality. - $diffs[$pointer -1][1] .= $diffs[$pointer +1][1]; - - $diffs[$pointer][1] = mb_substr($diffs[$pointer][1], mb_strlen($diffs[$pointer +1][1])) . $diffs[$pointer +1][1]; - array_splice($diffs, $pointer +1, 1); - $changes = true; - } - } - $pointer++; - } - // If shifts were made, the diff needs reordering and another shift sweep. - if ($changes) { - $this->diff_cleanupMerge($diffs); - } - } - - /** - * loc is a location in text1, compute and return the equivalent location in - * text2. - * e.g. 'The cat' vs 'The big cat', 1->1, 5->8 - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - * @param {number} loc Location within text1. - * @return {number} Location within text2. - */ - function diff_xIndex($diffs, $loc) { - $chars1 = 0; - $chars2 = 0; - $last_chars1 = 0; - $last_chars2 = 0; - for ($x = 0; $x < count($diffs); $x++) { - if ($diffs[$x][0] !== DIFF_INSERT) { // Equality or deletion. - $chars1 += mb_strlen($diffs[$x][1]); - } - if ($diffs[$x][0] !== DIFF_DELETE) { // Equality or insertion. - $chars2 += mb_strlen($diffs[$x][1]); - } - if ($chars1 > $loc) { // Overshot the location. - break; - } - $last_chars1 = $chars1; - $last_chars2 = $chars2; - } - // Was the location was deleted? - if (count($diffs) != $x && $diffs[$x][0] === DIFF_DELETE) { - return $last_chars2; - } - // Add the remaining character length. - return $last_chars2 + ($loc - $last_chars1); - } - - /** - * Convert a diff array into a pretty HTML report. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - * @return {string} HTML representation. - */ - function diff_prettyHtml($diffs) { - $html = array (); - $i = 0; - for ($x = 0; $x < count($diffs); $x++) { - $op = $diffs[$x][0]; // Operation (insert, delete, equal) - $data = $diffs[$x][1]; // Text of change. - $text = preg_replace(array ( - '/&/', - '/</', - '/>/', - "/\n/" - ), array ( - '&', - '<', - '>', - '¶<BR>' - ), $data); - - switch ($op) { - case DIFF_INSERT : - $html[$x] = '<INS STYLE="background:#E6FFE6;" TITLE="i=' . $i . '">' . $text . '</INS>'; - break; - case DIFF_DELETE : - $html[$x] = '<DEL STYLE="background:#FFE6E6;" TITLE="i=' . $i . '">' . $text . '</DEL>'; - break; - case DIFF_EQUAL : - $html[$x] = '<SPAN TITLE="i=' . $i . '">' . $text . '</SPAN>'; - break; - } - if ($op !== DIFF_DELETE) { - $i += mb_strlen($data); - } - } - return implode('',$html); - } - - /** - * Compute and return the source text (all equalities and deletions). - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - * @return {string} Source text. - */ - function diff_text1($diffs) { - $text = array (); - for ($x = 0; $x < count($diffs); $x++) { - if ($diffs[$x][0] !== DIFF_INSERT) { - $text[$x] = $diffs[$x][1]; - } - } - return implode('',$text); - } - - /** - * Compute and return the destination text (all equalities and insertions). - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - * @return {string} Destination text. - */ - function diff_text2($diffs) { - $text = array (); - for ($x = 0; $x < count($diffs); $x++) { - if ($diffs[$x][0] !== DIFF_DELETE) { - $text[$x] = $diffs[$x][1]; - } - } - return implode('',$text); - } - - /** - * Compute the Levenshtein distance; the number of inserted, deleted or - * substituted characters. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - * @return {number} Number of changes. - */ - function diff_levenshtein($diffs) { - $levenshtein = 0; - $insertions = 0; - $deletions = 0; - for ($x = 0; $x < count($diffs); $x++) { - $op = $diffs[$x][0]; - $data = $diffs[$x][1]; - switch ($op) { - case DIFF_INSERT : - $insertions += mb_strlen($data); - break; - case DIFF_DELETE : - $deletions += mb_strlen($data); - break; - case DIFF_EQUAL : - // A deletion and an insertion is one substitution. - $levenshtein += max($insertions, $deletions); - $insertions = 0; - $deletions = 0; - break; - } - } - $levenshtein += max($insertions, $deletions); - return $levenshtein; - } - - /** - * Crush the diff into an encoded string which describes the operations - * required to transform text1 into text2. - * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'. - * Operations are tab-separated. Inserted text is escaped using %xx notation. - * @param {Array.<Array.<number|string>>} diffs Array of diff tuples. - * @return {string} Delta text. - */ - function diff_toDelta($diffs) { - $text = array (); - for ($x = 0; $x < count($diffs); $x++) { - switch ($diffs[$x][0]) { - case DIFF_INSERT : - $text[$x] = '+' .encodeURI($diffs[$x][1]); - break; - case DIFF_DELETE : - $text[$x] = '-' .mb_strlen($diffs[$x][1]); - break; - case DIFF_EQUAL : - $text[$x] = '=' .mb_strlen($diffs[$x][1]); - break; - } - } - return str_replace('%20', ' ', implode("\t", $text)); - } - - /** - * Given the original text1, and an encoded string which describes the - * operations required to transform text1 into text2, compute the full diff. - * @param {string} text1 Source string for the diff. - * @param {string} delta Delta text. - * @return {Array.<Array.<number|string>>} Array of diff tuples. - * @throws {Error} If invalid input. - */ - function diff_fromDelta($text1, $delta) { - $diffs = array (); - $diffsLength = 0; // Keeping our own length var is faster in JS. - $pointer = 0; // Cursor in text1 - $tokens = preg_split("/\t/", $delta); - - for ($x = 0; $x < count($tokens); $x++) { - // Each token begins with a one character parameter which specifies the - // operation of this token (delete, insert, equality). - $param = mb_substr($tokens[$x], 1); - switch ($tokens[$x][0]) { - case '+' : - try { - $diffs[$diffsLength++] = array ( - DIFF_INSERT, - decodeURI($param) - ); - } catch (Exception $ex) { - echo_Exception('Illegal escape in diff_fromDelta: ' . $param); - // Malformed URI sequence. - } - break; - case '-' : - // Fall through. - case '=' : - $n = (int) $param; - if ($n < 0) { - echo_Exception('Invalid number in diff_fromDelta: ' . $param); - } - $text = mb_substr($text1, $pointer, $n); - $pointer += $n; - if ($tokens[$x][0] == '=') { - $diffs[$diffsLength++] = array ( - DIFF_EQUAL, - $text - ); - } else { - $diffs[$diffsLength++] = array ( - DIFF_DELETE, - $text - ); - } - break; - default : - // Blank tokens are ok (from a trailing \t). - // Anything else is an error. - if ($tokens[$x]) { - echo_Exception('Invalid diff operation in diff_fromDelta: ' . $tokens[$x]); - } - } - } - if ($pointer != mb_strlen($text1)) { -// throw new Exception('Delta length (' . $pointer . ') does not equal source text length (' . mb_strlen($text1) . ').'); - echo_Exception('Delta length (' . $pointer . ') does not equal source text length (' . mb_strlen($text1) . ').'); - } - return $diffs; - } - - // MATCH FUNCTIONS - - /** - * Locate the best instance of 'pattern' in 'text' near 'loc'. - * @param {string} text The text to search. - * @param {string} pattern The pattern to search for. - * @param {number} loc The location to search around. - * @return {number} Best match index or -1. - */ - function match_main($text, $pattern, $loc) { - $loc = max(0, min($loc, mb_strlen($text))); - if ($text == $pattern) { - // Shortcut (potentially not guaranteed by the algorithm) - return 0; - } - elseif (!mb_strlen($text)) { - // Nothing to match. - return -1; - } - elseif (mb_substr($text, $loc, mb_strlen($pattern)) == $pattern) { - // Perfect match at the perfect spot! (Includes case of null pattern) - return $loc; - } else { - // Do a fuzzy compare. - return $this->match_bitap($text, $pattern, $loc); - } - } - - /** - * Locate the best instance of 'pattern' in 'text' near 'loc' using the - * Bitap algorithm. - * @param {string} text The text to search. - * @param {string} pattern The pattern to search for. - * @param {number} loc The location to search around. - * @return {number} Best match index or -1. - * @private - */ - function match_bitap($text, $pattern, $loc) { - if (mb_strlen($pattern) > Match_MaxBits) { - echo_Exception('Pattern too long for this browser.'); - } - - // Initialise the alphabet. - $s = $this->match_alphabet($pattern); - - // Highest score beyond which we give up. - $score_threshold = $this->Match_Threshold; - - // Is there a nearby exact match? (speedup) - $best_loc = mb_strpos($text, $pattern, $loc); - if ($best_loc !== false) { - $score_threshold = min($this->match_bitapScore(0, $best_loc, $pattern, $loc), $score_threshold); - } - - // What about in the other direction? (speedup) - $best_loc = mb_strrpos( $text, $pattern, min($loc + mb_strlen($pattern), mb_strlen($text)) ); - if ($best_loc !== false) { - $score_threshold = min($this->match_bitapScore(0, $best_loc, $pattern, $loc), $score_threshold); - } - - // Initialise the bit arrays. - $matchmask = 1 << (mb_strlen($pattern) - 1); - $best_loc = -1; - - $bin_min = null; - $bin_mid = null; - $bin_max = mb_strlen($pattern) + mb_strlen($text); - $last_rd = null; - for ($d = 0; $d < mb_strlen($pattern); $d++) { - // Scan for the best match; each iteration allows for one more error. - // Run a binary search to determine how far from 'loc' we can stray at this - // error level. - $bin_min = 0; - $bin_mid = $bin_max; - while ($bin_min < $bin_mid) { - if ($this->match_bitapScore($d, $loc + $bin_mid, $pattern, $loc) <= $score_threshold) { - $bin_min = $bin_mid; - } else { - $bin_max = $bin_mid; - } - $bin_mid = floor(($bin_max - $bin_min) / 2 + $bin_min); - } - // Use the result from this iteration as the maximum for the next. - $bin_max = $bin_mid; - $start = max(1, $loc - $bin_mid +1); - $finish = min($loc + $bin_mid, mb_strlen($text)) + mb_strlen($pattern); - - $rd = Array ( - $finish +2 - ); - $rd[$finish +1] = (1 << $d) - 1; - for ($j = $finish; $j >= $start; $j--) { - // The alphabet (s) is a sparse hash, so the following line generates - // warnings. -@ $charMatch = $s[ $text[$j -1] ]; - if ($d === 0) { // First pass: exact match. - $rd[$j] = (($rd[$j +1] << 1) | 1) & $charMatch; - } else { // Subsequent passes: fuzzy match. - $rd[$j] = (($rd[$j +1] << 1) | 1) & $charMatch | ((($last_rd[$j +1] | $last_rd[$j]) << 1) | 1) | $last_rd[$j +1]; - } - if ($rd[$j] & $matchmask) { - $score = $this->match_bitapScore($d, $j -1, $pattern, $loc); - // This match will almost certainly be better than any existing match. - // But check anyway. - if ($score <= $score_threshold) { - // Told you so. - $score_threshold = $score; - $best_loc = $j -1; - if ($best_loc > $loc) { - // When passing loc, don't exceed our current distance from loc. - $start = max(1, 2 * $loc - $best_loc); - } else { - // Already passed loc, downhill from here on in. - break; - } - } - } - } - // No hope for a (better) match at greater error levels. - if ($this->match_bitapScore($d +1, $loc, $pattern, $loc) > $score_threshold) { - break; - } - $last_rd = $rd; - } - return (int)$best_loc; - } - - /** - * Compute and return the score for a match with e errors and x location. - * Accesses loc and pattern through being a closure. - * @param {number} e Number of errors in match. - * @param {number} x Location of match. - * @return {number} Overall score for match (0.0 = good, 1.0 = bad). - * @private - */ - function match_bitapScore($e, $x, $pattern, $loc) { - $accuracy = $e / mb_strlen($pattern); - $proximity = abs($loc - $x); - if (!$this->Match_Distance) { - // Dodge divide by zero error. - return $proximity ? 1.0 : $accuracy; - } - return $accuracy + ($proximity / $this->Match_Distance); - } - - /** - * Initialise the alphabet for the Bitap algorithm. - * @param {string} pattern The text to encode. - * @return {Object} Hash of character locations. - * @private - */ - function match_alphabet($pattern) { - $s = array (); - for ($i = 0; $i < mb_strlen($pattern); $i++) { - $s[ $pattern[$i] ] = 0; - } - for ($i = 0; $i < mb_strlen($pattern); $i++) { - $s[ $pattern[$i] ] |= 1 << (mb_strlen($pattern) - $i - 1); - } - return $s; - } - - // PATCH FUNCTIONS - - /** - * Increase the context until it is unique, - * but don't let the pattern expand beyond Match_MaxBits. - * @param {patch_obj} patch The patch to grow. - * @param {string} text Source text. - * @private - */ - function patch_addContext($patch, $text) { - $pattern = mb_substr($text, $patch->start2, $patch->length1 ); - $previousPattern = null; - $padding = 0; - $i = 0; - while ( - ( mb_strlen($pattern) === 0 // Javascript's indexOf/lastIndexOd return 0/strlen respectively if pattern = '' - || mb_strpos($text, $pattern) !== mb_strrpos($text, $pattern) - ) - && $pattern !== $previousPattern // avoid infinte loop - && mb_strlen($pattern) < Match_MaxBits - $this->Patch_Margin - $this->Patch_Margin ) { - $padding += $this->Patch_Margin; - $previousPattern = $pattern; - $pattern = mb_substr($text, max($patch->start2 - $padding,0), ($patch->start2 + $patch->length1 + $padding) - max($patch->start2 - $padding,0) ); - } - // Add one chunk for good luck. - $padding += $this->Patch_Margin; - // Add the prefix. - $prefix = mb_substr($text, max($patch->start2 - $padding,0), $patch->start2 - max($patch->start2 - $padding,0) ); - if ($prefix!=='') { - array_unshift($patch->diffs, array ( - DIFF_EQUAL, - $prefix - )); - } - // Add the suffix. - $suffix = mb_substr($text, $patch->start2 + $patch->length1, ($patch->start2 + $patch->length1 + $padding) - ($patch->start2 + $patch->length1) ); - if ($suffix!=='') { - array_push($patch->diffs, array ( - DIFF_EQUAL, - $suffix - )); - } - - // Roll back the start points. - $patch->start1 -= mb_strlen($prefix); - $patch->start2 -= mb_strlen($prefix); - // Extend the lengths. - $patch->length1 += mb_strlen($prefix) + mb_strlen($suffix); - $patch->length2 += mb_strlen($prefix) + mb_strlen($suffix); - } - - /** - * Compute a list of patches to turn text1 into text2. - * Use diffs if provided, otherwise compute it ourselves. - * There are four ways to call this function, depending on what data is - * available to the caller: - * Method 1: - * a = text1, b = text2 - * Method 2: - * a = diffs - * Method 3 (optimal): - * a = text1, b = diffs - * Method 4 (deprecated, use method 3): - * a = text1, b = text2, c = diffs - * - * @param {string|Array.<Array.<number|string>>} a text1 (methods 1,3,4) or - * Array of diff tuples for text1 to text2 (method 2). - * @param {string|Array.<Array.<number|string>>} opt_b text2 (methods 1,4) or - * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2). - * @param {string|Array.<Array.<number|string>>} opt_c Array of diff tuples for - * text1 to text2 (method 4) or undefined (methods 1,2,3). - * @return {Array.<patch_obj>} Array of patch objects. - */ - function patch_make($a, $opt_b = null, $opt_c = null ) { - if (is_string($a) && is_string($opt_b) && $opt_c === null ) { - // Method 1: text1, text2 - // Compute diffs from text1 and text2. - $text1 = $a; - $diffs = $this->diff_main($text1, $opt_b, true); - if ( count($diffs) > 2) { - $this->diff_cleanupSemantic($diffs); - $this->diff_cleanupEfficiency($diffs); - } - } elseif ( is_array($a) && $opt_b === null && $opt_c === null) { - // Method 2: diffs - // Compute text1 from diffs. - $diffs = $a; - $text1 = $this->diff_text1($diffs); - } elseif ( is_string($a) && is_array($opt_b) && $opt_c === null) { - // Method 3: text1, diffs - $text1 = $a; - $diffs = $opt_b; - } elseif ( is_string($a) && is_string($opt_b) && is_array($opt_c) ) { - // Method 4: text1, text2, diffs - // text2 is not used. - $text1 = $a; - $diffs = $opt_c; - } else { - echo_Exception('Unknown call format to patch_make.'); - } - - if ( count($diffs) === 0) { - return array(); // Get rid of the null case. - } - $patches = array(); - $patch = new patch_obj(); - $patchDiffLength = 0; // Keeping our own length var is faster in JS. - $char_count1 = 0; // Number of characters into the text1 string. - $char_count2 = 0; // Number of characters into the text2 string. - // Start with text1 (prepatch_text) and apply the diffs until we arrive at - // text2 (postpatch_text). We recreate the patches one by one to determine - // context info. - $prepatch_text = $text1; - $postpatch_text = $text1; - for ($x = 0; $x < count($diffs); $x++) { - $diff_type = $diffs[$x][0]; - $diff_text = $diffs[$x][1]; - - if (!$patchDiffLength && $diff_type !== DIFF_EQUAL) { - // A new patch starts here. - $patch->start1 = $char_count1; - $patch->start2 = $char_count2; - } - - switch ($diff_type) { - case DIFF_INSERT : - $patch->diffs[$patchDiffLength++] = $diffs[$x]; - $patch->length2 += mb_strlen($diff_text); - $postpatch_text = mb_substr($postpatch_text, 0, $char_count2) . $diff_text . mb_substr($postpatch_text,$char_count2); - break; - case DIFF_DELETE : - $patch->length1 += mb_strlen($diff_text); - $patch->diffs[$patchDiffLength++] = $diffs[$x]; - $postpatch_text = mb_substr($postpatch_text, 0, $char_count2) . mb_substr($postpatch_text, $char_count2 + mb_strlen($diff_text) ); - break; - case DIFF_EQUAL : - if ( mb_strlen($diff_text) <= 2 * $this->Patch_Margin && $patchDiffLength && count($diffs) != $x + 1) { - // Small equality inside a patch. - $patch->diffs[$patchDiffLength++] = $diffs[$x]; - $patch->length1 += mb_strlen($diff_text); - $patch->length2 += mb_strlen($diff_text); - } elseif ( mb_strlen($diff_text) >= 2 * $this->Patch_Margin ) { - // Time for a new patch. - if ($patchDiffLength) { - $this->patch_addContext($patch, $prepatch_text); - array_push($patches,$patch); - $patch = new patch_obj(); - $patchDiffLength = 0; - // Unlike Unidiff, our patch lists have a rolling context. - // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff - // Update prepatch text & pos to reflect the application of the - // just completed patch. - $prepatch_text = $postpatch_text; - $char_count1 = $char_count2; - } - } - break; - } - - // Update the current character count. - if ($diff_type !== DIFF_INSERT) { - $char_count1 += mb_strlen($diff_text); - } - if ($diff_type !== DIFF_DELETE) { - $char_count2 += mb_strlen($diff_text); - } - } - // Pick up the leftover patch if not empty. - if ($patchDiffLength) { - $this->patch_addContext($patch, $prepatch_text); - array_push($patches, $patch); - } - - return $patches; - } - - /** - * Given an array of patches, return another array that is identical. - * @param {Array.<patch_obj>} patches Array of patch objects. - * @return {Array.<patch_obj>} Array of patch objects. - */ - function patch_deepCopy($patches) { - // Making deep copies is hard in JavaScript. - $patchesCopy = array(); - for ($x = 0; $x < count($patches); $x++) { - $patch = $patches[$x]; - $patchCopy = new patch_obj(); - for ($y = 0; $y < count($patch->diffs); $y++) { - $patchCopy->diffs[$y] = $patch->diffs[$y]; // ?? . slice(); - } - $patchCopy->start1 = $patch->start1; - $patchCopy->start2 = $patch->start2; - $patchCopy->length1 = $patch->length1; - $patchCopy->length2 = $patch->length2; - $patchesCopy[$x] = $patchCopy; - } - return $patchesCopy; - } - - /** - * Merge a set of patches onto the text. Return a patched text, as well - * as a list of true/false values indicating which patches were applied. - * @param {Array.<patch_obj>} patches Array of patch objects. - * @param {string} text Old text. - * @return {Array.<string|Array.<boolean>>} Two element Array, containing the - * new text and an array of boolean values. - */ - function patch_apply($patches, $text) { - if ( count($patches) == 0) { - return array($text,array()); - } - - // Deep copy the patches so that no changes are made to originals. - $patches = $this->patch_deepCopy($patches); - - $nullPadding = $this->patch_addPadding($patches); - $text = $nullPadding . $text . $nullPadding; - - $this->patch_splitMax($patches); - // delta keeps track of the offset between the expected and actual location - // of the previous patch. If there are patches expected at positions 10 and - // 20, but the first patch was found at 12, delta is 2 and the second patch - // has an effective expected position of 22. - $delta = 0; - $results = array(); - for ($x = 0; $x < count($patches) ; $x++) { - $expected_loc = $patches[$x]->start2 + $delta; - $text1 = $this->diff_text1($patches[$x]->diffs); - $start_loc = null; - $end_loc = -1; - if (mb_strlen($text1) > Match_MaxBits) { - // patch_splitMax will only provide an oversized pattern in the case of - // a monster delete. - $start_loc = $this->match_main($text, mb_substr($text1, 0, Match_MaxBits ), $expected_loc); - if ($start_loc != -1) { - $end_loc = $this->match_main($text, mb_substr($text1,mb_strlen($text1) - Match_MaxBits), $expected_loc + mb_strlen($text1) - Match_MaxBits); - if ($end_loc == -1 || $start_loc >= $end_loc) { - // Can't find valid trailing context. Drop this patch. - $start_loc = -1; - } - } - } else { - $start_loc = $this->match_main($text, $text1, $expected_loc); - } - if ($start_loc == -1) { - // No match found. :( - $results[$x] = false; - // Subtract the delta for this failed patch from subsequent patches. - $delta -= $patches[$x]->length2 - $patches[$x]->length1; - } else { - // Found a match. :) - $results[$x] = true; - $delta = $start_loc - $expected_loc; - $text2 = null; - if ($end_loc == -1) { - $text2 = mb_substr($text, $start_loc, mb_strlen($text1) ); - } else { - $text2 = mb_substr($text, $start_loc, $end_loc + Match_MaxBits - $start_loc); - } - if ($text1 == $text2) { - // Perfect match, just shove the replacement text in. - $text = mb_substr($text, 0, $start_loc) . $this->diff_text2($patches[$x]->diffs) . mb_substr($text,$start_loc + mb_strlen($text1) ); - } else { - // Imperfect match. Run a diff to get a framework of equivalent - // indices. - $diffs = $this->diff_main($text1, $text2, false); - if ( mb_strlen($text1) > Match_MaxBits && $this->diff_levenshtein($diffs) / mb_strlen($text1) > $this->Patch_DeleteThreshold) { - // The end points match, but the content is unacceptably bad. - $results[$x] = false; - } else { - $this->diff_cleanupSemanticLossless($diffs); - $index1 = 0; - $index2 = NULL; - for ($y = 0; $y < count($patches[$x]->diffs); $y++) { - $mod = $patches[$x]->diffs[$y]; - if ($mod[0] !== DIFF_EQUAL) { - $index2 = $this->diff_xIndex($diffs, $index1); - } - if ($mod[0] === DIFF_INSERT) { // Insertion - $text = mb_substr($text, 0, $start_loc + $index2) . $mod[1] . mb_substr($text, $start_loc + $index2); - } elseif ($mod[0] === DIFF_DELETE) { // Deletion - $text = mb_substr($text, 0, $start_loc + $index2) . mb_substr($text,$start_loc + $this->diff_xIndex($diffs, $index1 + mb_strlen($mod[1]) )); - } - if ($mod[0] !== DIFF_DELETE) { - $index1 += mb_strlen($mod[1]); - } - } - } - } - } - } - // Strip the padding off. - $text = mb_substr($text, mb_strlen($nullPadding), mb_strlen($text) - 2*mb_strlen($nullPadding) ); - return array($text, $results); - } - - /** - * Add some padding on text start and end so that edges can match something. - * Intended to be called only from within patch_apply. - * @param {Array.<patch_obj>} patches Array of patch objects. - * @return {string} The padding string added to each side. - */ - function patch_addPadding(&$patches){ - $paddingLength = $this->Patch_Margin; - $nullPadding = ''; - for ($x = 1; $x <= $paddingLength; $x++) { - $nullPadding .= mb_chr($x); - } - - // Bump all the patches forward. - for ($x = 0; $x < count($patches); $x++) { - $patches[$x]->start1 += $paddingLength; - $patches[$x]->start2 += $paddingLength; - } - - // Add some padding on start of first diff. - $patch = &$patches[0]; - $diffs = &$patch->diffs; - if (count($diffs) == 0 || $diffs[0][0] != DIFF_EQUAL) { - // Add nullPadding equality. - array_unshift($diffs, array(DIFF_EQUAL, $nullPadding)); - $patch->start1 -= $paddingLength; // Should be 0. - $patch->start2 -= $paddingLength; // Should be 0. - $patch->length1 += $paddingLength; - $patch->length2 += $paddingLength; - } elseif ($paddingLength > mb_strlen($diffs[0][1]) ) { - // Grow first equality. - $extraLength = $paddingLength - mb_strlen($diffs[0][1]); - $diffs[0][1] = mb_substr( $nullPadding , mb_strlen($diffs[0][1]) ) . $diffs[0][1]; - $patch->start1 -= $extraLength; - $patch->start2 -= $extraLength; - $patch->length1 += $extraLength; - $patch->length2 += $extraLength; - } - - // Add some padding on end of last diff. - $patch = &$patches[count($patches) - 1]; - $diffs = &$patch->diffs; - if ( count($diffs) == 0 || $diffs[ count($diffs) - 1][0] != DIFF_EQUAL) { - // Add nullPadding equality. - array_push($diffs, array(DIFF_EQUAL, $nullPadding) ); - $patch->length1 += $paddingLength; - $patch->length2 += $paddingLength; - } elseif ($paddingLength > mb_strlen( $diffs[count($diffs)-1][1] ) ) { - // Grow last equality. - $extraLength = $paddingLength - mb_strlen( $diffs[count($diffs)-1][1] ); - $diffs[ count($diffs)-1][1] .= mb_substr($nullPadding,0,$extraLength); - $patch->length1 += $extraLength; - $patch->length2 += $extraLength; - } - - return $nullPadding; - } - - /** - * Look through the patches and break up any which are longer than the maximum - * limit of the match algorithm. - * @param {Array.<patch_obj>} patches Array of patch objects. - */ - function patch_splitMax(&$patches) { - for ($x = 0; $x < count($patches); $x++) { - if ( $patches[$x]->length1 > Match_MaxBits) { - $bigpatch = $patches[$x]; - // Remove the big old patch. - array_splice($patches,$x--,1); - $patch_size = Match_MaxBits; - $start1 = $bigpatch->start1; - $start2 = $bigpatch->start2; - $precontext = ''; - while ( count($bigpatch->diffs) !== 0) { - // Create one of several smaller patches. - $patch = new patch_obj(); - $empty = true; - $patch->start1 = $start1 - mb_strlen($precontext); - $patch->start2 = $start2 - mb_strlen($precontext); - if ($precontext !== '') { - $patch->length1 = $patch->length2 = mb_strlen($precontext); - array_push($patch->diffs, array(DIFF_EQUAL, $precontext) ); - } - while ( count($bigpatch->diffs) !== 0 && $patch->length1 < $patch_size - $this->Patch_Margin) { - $diff_type = $bigpatch->diffs[0][0]; - $diff_text = $bigpatch->diffs[0][1]; - if ($diff_type === DIFF_INSERT) { - // Insertions are harmless. - $patch->length2 += mb_strlen($diff_text); - $start2 += mb_strlen($diff_text); - array_push($patch->diffs, array_shift($bigpatch->diffs) ); - $empty = false; - } else - if ($diff_type === DIFF_DELETE && count($patch->diffs) == 1 && $patch->diffs[0][0] == DIFF_EQUAL && (mb_strlen($diff_text) > 2 * $patch_size) ) { - // This is a large deletion. Let it pass in one chunk. - $patch->length1 += mb_strlen($diff_text); - $start1 += mb_strlen($diff_text); - $empty = false; - array_push( $patch->diffs, array($diff_type, $diff_text) ); - array_shift($bigpatch->diffs); - } else { - // Deletion or equality. Only take as much as we can stomach. - $diff_text = mb_substr($diff_text, 0, $patch_size - $patch->length1 - $this->Patch_Margin); - $patch->length1 += mb_strlen($diff_text); - $start1 += mb_strlen($diff_text); - if ($diff_type === DIFF_EQUAL) { - $patch->length2 += mb_strlen($diff_text); - $start2 += mb_strlen($diff_text); - } else { - $empty = false; - } - array_push($patch->diffs, array($diff_type, $diff_text) ); - if ($diff_text == $bigpatch->diffs[0][1]) { - array_shift($bigpatch->diffs); - } else { - $bigpatch->diffs[0][1] = mb_substr( $bigpatch->diffs[0][1],mb_strlen($diff_text) ); - } - } - } - // Compute the head context for the next patch. - $precontext = $this->diff_text2($patch->diffs); - $precontext = mb_substr($precontext, mb_strlen($precontext)-$this->Patch_Margin); - // Append the end context for this patch. - $postcontext = mb_substr( $this->diff_text1($bigpatch->diffs), 0, $this->Patch_Margin ); - if ($postcontext !== '') { - $patch->length1 += mb_strlen($postcontext); - $patch->length2 += mb_strlen($postcontext); - if ( count($patch->diffs) !== 0 && $patch->diffs[ count($patch->diffs) - 1][0] === DIFF_EQUAL) { - $patch->diffs[ count($patch->diffs) - 1][1] .= $postcontext; - } else { - array_push($patch->diffs, array(DIFF_EQUAL, $postcontext)); - } - } - if (!$empty) { - array_splice($patches, ++$x, 0, array($patch)); - } - } - } - } - } - - /** - * Take a list of patches and return a textual representation. - * @param {Array.<patch_obj>} patches Array of patch objects. - * @return {string} Text representation of patches. - */ - function patch_toText($patches) { - $text = array(); - for ($x = 0; $x < count($patches) ; $x++) { - $text[$x] = $patches[$x]; - } - return implode('',$text); - } - - /** - * Parse a textual representation of patches and return a list of patch objects. - * @param {string} textline Text representation of patches. - * @return {Array.<patch_obj>} Array of patch objects. - * @throws {Error} If invalid input. - */ - function patch_fromText($textline) { - $patches = array(); - if ($textline === '') { - return $patches; - } - $text = explode("\n",$textline); - foreach($text as $i=>$t){ if($t===''){ unset($text[$i]); } } - $textPointer = 0; - while ($textPointer < count($text) ) { - $m = null; - preg_match('/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/',$text[$textPointer],$m); - if (!$m) { - echo_Exception('Invalid patch string: ' . $text[$textPointer]); - } - $patch = new patch_obj(); - array_push($patches, $patch); - @$patch->start1 = (int)$m[1]; - if (@$m[2] === '') { - $patch->start1--; - $patch->length1 = 1; - } elseif ( @$m[2] == '0') { - $patch->length1 = 0; - } else { - $patch->start1--; - @$patch->length1 = (int)$m[2]; - } - - @$patch->start2 = (int)$m[3]; - if (@$m[4] === '') { - $patch->start2--; - $patch->length2 = 1; - } elseif ( @$m[4] == '0') { - $patch->length2 = 0; - } else { - $patch->start2--; - @$patch->length2 = (int)$m[4]; - } - $textPointer++; - - while ($textPointer < count($text) ) { - $sign = $text[$textPointer][0]; - try { - $line = decodeURI( mb_substr($text[$textPointer],1) ); - } catch (Exception $ex) { - // Malformed URI sequence. - throw new Exception('Illegal escape in patch_fromText: ' . $line); - } - if ($sign == '-') { - // Deletion. - array_push( $patch->diffs, array(DIFF_DELETE, $line) ); - } elseif ($sign == '+') { - // Insertion. - array_push($patch->diffs, array(DIFF_INSERT, $line) ); - } elseif ($sign == ' ') { - // Minor equality. - array_push($patch->diffs, array(DIFF_EQUAL, $line) ); - } elseif ($sign == '@') { - // Start of next patch. - break; - } elseif ($sign === '') { - // Blank line? Whatever. - } else { - // WTF? - echo_Exception('Invalid patch mode "' . $sign . '" in: ' . $line); - } - $textPointer++; - } - } - return $patches; - } -} - -/** - * Class representing one patch operation. - * @constructor - */ -class patch_obj { - /** @type {Array.<Array.<number|string>>} */ - public $diffs = array(); - /** @type {number?} */ - public $start1 = null; - /** @type {number?} */ - public $start2 = null; - /** @type {number} */ - public $length1 = 0; - /** @type {number} */ - public $length2 = 0; - - /** - * Emmulate GNU diff's format. - * Header: @@ -382,8 +481,9 @@ - * Indicies are printed as 1-based, not 0-based. - * @return {string} The GNU diff string. - */ - function toString() { - if ($this->length1 === 0) { - $coords1 = $this->start1 . ',0'; - } elseif ($this->length1 == 1) { - $coords1 = $this->start1 + 1; - } else { - $coords1 = ($this->start1 + 1) . ',' . $this->length1; - } - if ($this->length2 === 0) { - $coords2 = $this->start2 . ',0'; - } elseif ($this->length2 == 1) { - $coords2 = $this->start2 + 1; - } else { - $coords2 = ($this->start2 + 1) . ',' . $this->length2; - } - $text = array ( '@@ -' . $coords1 . ' +' . $coords2 . " @@\n" ); - - // Escape the body of the patch with %xx notation. - for ($x = 0; $x < count($this->diffs); $x++) { - switch ($this->diffs[$x][0]) { - case DIFF_INSERT : - $op = '+'; - break; - case DIFF_DELETE : - $op = '-'; - break; - case DIFF_EQUAL : - $op = ' '; - break; - } - $text[$x +1] = $op . encodeURI($this->diffs[$x][1]) . "\n"; - } - return str_replace('%20', ' ', implode('',$text)); - } - function __toString(){ - return $this->toString(); - } -} - -define('DIFF_DELETE', -1); -define('DIFF_INSERT', 1); -define('DIFF_EQUAL', 0); - -define('Match_MaxBits', PHP_INT_SIZE * 8); - - -function charCodeAt($str, $pos) { - return mb_ord(mb_substr($str, $pos, 1)); -} -function mb_ord($v) { - $k = mb_convert_encoding($v, 'UCS-2LE', 'UTF-8'); - $k1 = ord(substr($k, 0, 1)); - $k2 = ord(substr($k, 1, 1)); - return $k2 * 256 + $k1; -} -function mb_chr($num){ - return mb_convert_encoding('&#'.intval($num).';', 'UTF-8', 'HTML-ENTITIES'); -} - -/** - * as in javascript encodeURI() following the MDN description - * - * @link https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURI - * @param $url - * @return string - */ -function encodeURI($url) { - return strtr(rawurlencode($url), array ( - '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', '%26' => '&', '%3D' => '=', - '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#', - )); -} - -function decodeURI($encoded) { - static $dontDecode; - if (!$dontDecode) { - $table = array ( - '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', '%26' => '&', '%3D' => '=', - '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#', - ); - $dontDecode = array(); - foreach ($table as $k => $v) { - $dontDecode[$k] = encodeURI($k); - } - } - return rawurldecode(strtr($encoded, $dontDecode)); -} - -function echo_Exception($str){ - global $lastException; - $lastException = $str; - echo $str; -} -//mb_internal_encoding("UTF-8"); - -?> \ No newline at end of file diff -Nru phabricator-0~git20200925/phabricator/NOTICE phabricator-0~git20220903/phabricator/NOTICE --- phabricator-0~git20200925/phabricator/NOTICE 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/NOTICE 2022-06-14 16:29:55.000000000 +0000 @@ -1,7 +1,7 @@ Phabricator Copyright 2014 Phacility, Inc. -This software is primarily developed and maintained by Phacility, Inc. +Phabricator was originally developed and maintained by Phacility, Inc. http://www.phacility.com/ diff -Nru phabricator-0~git20200925/phabricator/README.md phabricator-0~git20220903/phabricator/README.md --- phabricator-0~git20200925/phabricator/README.md 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/README.md 2022-06-14 16:29:55.000000000 +0000 @@ -1,30 +1,6 @@ -**Phabricator** is a collection of web applications which help software companies build better software. +Effective June 1, 2021: Phabricator is no longer actively maintained. -Phabricator includes applications for: - - - reviewing and auditing source code; - - hosting and browsing repositories; - - tracking bugs; - - managing projects; - - conversing with team members; - - assembling a party to venture forth; - - writing stuff down and reading it later; - - hiding stuff from coworkers; and - - also some other things. - -You can learn more about the project (and find links to documentation and resources) at [Phabricator.org](http://phabricator.org) - -Phabricator is developed and maintained by [Phacility](http://phacility.com). - ----------- - -**SUPPORT RESOURCES** - -For resources on filing bugs, requesting features, reporting security issues, and getting other kinds of support, see [Support Resources](https://secure.phabricator.com/book/phabricator/article/support/). - -**NO PULL REQUESTS!** - -We do not accept pull requests through GitHub. If you would like to contribute code, please read our [Contributor's Guide](https://secure.phabricator.com/book/phabcontrib/article/contributing_code/). +**Phabricator** is a collection of web applications for software development. **LICENSE** diff -Nru phabricator-0~git20200925/phabricator/resources/celerity/map.php phabricator-0~git20220903/phabricator/resources/celerity/map.php --- phabricator-0~git20200925/phabricator/resources/celerity/map.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/celerity/map.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,13 +9,13 @@ 'names' => array( 'conpherence.pkg.css' => '0e3cf785', 'conpherence.pkg.js' => '020aebcf', - 'core.pkg.css' => 'bd937962', - 'core.pkg.js' => 'adc34883', + 'core.pkg.css' => 'b816811e', + 'core.pkg.js' => 'd2de90d9', 'dark-console.pkg.js' => '187792c2', - 'differential.pkg.css' => '5c459f92', - 'differential.pkg.js' => '218fda21', + 'differential.pkg.css' => 'ffb69e3d', + 'differential.pkg.js' => 'c60bec1b', 'diffusion.pkg.css' => '42c75c37', - 'diffusion.pkg.js' => '8ee48a4b', + 'diffusion.pkg.js' => '78c9885d', 'maniphest.pkg.css' => '35995d6d', 'maniphest.pkg.js' => 'c9308721', 'rsrc/audio/basic/alert.mp3' => '17889334', @@ -67,7 +67,7 @@ 'rsrc/css/application/differential/core.css' => '7300a73e', 'rsrc/css/application/differential/phui-inline-comment.css' => '9863a85e', 'rsrc/css/application/differential/revision-comment.css' => '7dbc8d1d', - 'rsrc/css/application/differential/revision-history.css' => '8aa3eac5', + 'rsrc/css/application/differential/revision-history.css' => '237a2979', 'rsrc/css/application/differential/revision-list.css' => '93d2df7d', 'rsrc/css/application/differential/table-of-contents.css' => 'bba788b9', 'rsrc/css/application/diffusion/diffusion-icons.css' => '23b31a1b', @@ -78,7 +78,7 @@ 'rsrc/css/application/files/global-drag-and-drop.css' => '1d2713a4', 'rsrc/css/application/flag/flag.css' => '2b77be8d', 'rsrc/css/application/harbormaster/harbormaster.css' => '8dfe16b2', - 'rsrc/css/application/herald/herald-test.css' => 'e004176f', + 'rsrc/css/application/herald/herald-test.css' => '7e7bbdae', 'rsrc/css/application/herald/herald.css' => '648d39e2', 'rsrc/css/application/maniphest/report.css' => '3d53188b', 'rsrc/css/application/maniphest/task-edit.css' => '272daa84', @@ -101,20 +101,16 @@ 'rsrc/css/application/policy/policy-transaction-detail.css' => 'c02b8384', 'rsrc/css/application/policy/policy.css' => 'ceb56a08', 'rsrc/css/application/ponder/ponder-view.css' => '05a09d0a', - 'rsrc/css/application/project/project-card-view.css' => '4e7371cd', + 'rsrc/css/application/project/project-card-view.css' => 'a9f2c2dd', 'rsrc/css/application/project/project-triggers.css' => 'cd9c8bb9', 'rsrc/css/application/project/project-view.css' => '567858b3', - 'rsrc/css/application/releeph/releeph-core.css' => 'f81ff2db', - 'rsrc/css/application/releeph/releeph-preview-branch.css' => '22db5c07', - 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '0ac1ea31', - 'rsrc/css/application/releeph/releeph-request-typeahead.css' => 'bce37359', 'rsrc/css/application/search/application-search-view.css' => '0f7c06d8', 'rsrc/css/application/search/search-results.css' => '9ea70ace', 'rsrc/css/application/slowvote/slowvote.css' => '1694baed', 'rsrc/css/application/tokens/tokens.css' => 'ce5a50bd', 'rsrc/css/application/uiexample/example.css' => 'b4795059', 'rsrc/css/core/core.css' => 'b3ebd90d', - 'rsrc/css/core/remarkup.css' => '94c3d777', + 'rsrc/css/core/remarkup.css' => '5baa3bd9', 'rsrc/css/core/syntax.css' => '548567f6', 'rsrc/css/core/z-index.css' => 'ac3bfcd4', 'rsrc/css/diviner/diviner-shared.css' => '4bd263b0', @@ -151,7 +147,7 @@ 'rsrc/css/phui/phui-comment-form.css' => '68a2d99a', 'rsrc/css/phui/phui-comment-panel.css' => 'ec4e31c0', 'rsrc/css/phui/phui-crumbs-view.css' => '614f43cf', - 'rsrc/css/phui/phui-curtain-object-ref-view.css' => '12404744', + 'rsrc/css/phui/phui-curtain-object-ref-view.css' => '51d93266', 'rsrc/css/phui/phui-curtain-view.css' => '68c5efb6', 'rsrc/css/phui/phui-document-pro.css' => 'b9613a10', 'rsrc/css/phui/phui-document-summary.css' => 'b068eed1', @@ -171,7 +167,7 @@ 'rsrc/css/phui/phui-invisible-character-view.css' => 'c694c4a4', 'rsrc/css/phui/phui-left-right.css' => '68513c34', 'rsrc/css/phui/phui-lightbox.css' => '4ebf22da', - 'rsrc/css/phui/phui-list.css' => '2f253c22', + 'rsrc/css/phui/phui-list.css' => '0c04affd', 'rsrc/css/phui/phui-object-box.css' => 'b8d7eea0', 'rsrc/css/phui/phui-pager.css' => 'd022c7ad', 'rsrc/css/phui/phui-pinboard-view.css' => '1f08f5d8', @@ -180,8 +176,8 @@ 'rsrc/css/phui/phui-remarkup-preview.css' => '91767007', 'rsrc/css/phui/phui-segment-bar-view.css' => '5166b370', 'rsrc/css/phui/phui-spacing.css' => 'b05cadc3', - 'rsrc/css/phui/phui-status.css' => 'e5ff8be0', - 'rsrc/css/phui/phui-tag-view.css' => '8519160a', + 'rsrc/css/phui/phui-status.css' => '293b5dad', + 'rsrc/css/phui/phui-tag-view.css' => 'fb811341', 'rsrc/css/phui/phui-timeline-view.css' => '2d32d7a9', 'rsrc/css/phui/phui-two-column-view.css' => 'f96d319f', 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'e86de308', @@ -246,14 +242,14 @@ 'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => 'a9f35511', 'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '3a1b81f6', 'rsrc/externals/javelin/lib/Cookie.js' => '05d290ef', - 'rsrc/externals/javelin/lib/DOM.js' => '94681e22', + 'rsrc/externals/javelin/lib/DOM.js' => 'e4c7622a', 'rsrc/externals/javelin/lib/History.js' => '030b4f7a', 'rsrc/externals/javelin/lib/JSON.js' => '541f81c3', 'rsrc/externals/javelin/lib/Leader.js' => '0d2490ce', 'rsrc/externals/javelin/lib/Mask.js' => '7c4d8998', 'rsrc/externals/javelin/lib/Quicksand.js' => 'd3799cb4', 'rsrc/externals/javelin/lib/Request.js' => '84e6891f', - 'rsrc/externals/javelin/lib/Resource.js' => '740956e1', + 'rsrc/externals/javelin/lib/Resource.js' => '20514cc2', 'rsrc/externals/javelin/lib/Routable.js' => '6a18c42e', 'rsrc/externals/javelin/lib/Router.js' => '32755edb', 'rsrc/externals/javelin/lib/Scrollbar.js' => 'a43ae2ae', @@ -383,9 +379,10 @@ 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', - 'rsrc/js/application/diff/DiffChangeset.js' => '39dcf2c3', + 'rsrc/js/application/diff/DiffChangeset.js' => 'd7d3ba75', 'rsrc/js/application/diff/DiffChangesetList.js' => 'cc2c5de5', - 'rsrc/js/application/diff/DiffInline.js' => '511a1315', + 'rsrc/js/application/diff/DiffInline.js' => '9c775532', + 'rsrc/js/application/diff/DiffInlineContentState.js' => 'aa51efb4', 'rsrc/js/application/diff/DiffPathView.js' => '8207abf9', 'rsrc/js/application/diff/DiffTreeView.js' => '5d83623b', 'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd', @@ -394,7 +391,7 @@ 'rsrc/js/application/diffusion/ExternalEditorLinkEngine.js' => '48a8641f', 'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'b7b73831', 'rsrc/js/application/diffusion/behavior-commit-branches.js' => '4b671572', - 'rsrc/js/application/diffusion/behavior-commit-graph.js' => '3be6ef4f', + 'rsrc/js/application/diffusion/behavior-commit-graph.js' => 'ac10c917', 'rsrc/js/application/diffusion/behavior-locate-file.js' => '87428eb2', 'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'c715c123', 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '6a85bc5a', @@ -434,10 +431,7 @@ 'rsrc/js/application/projects/behavior-project-boards.js' => '58cb6a88', 'rsrc/js/application/projects/behavior-project-create.js' => '34c53422', 'rsrc/js/application/projects/behavior-reorder-columns.js' => '8ac32fd9', - 'rsrc/js/application/releeph/releeph-preview-branch.js' => '75184d68', - 'rsrc/js/application/releeph/releeph-request-state-change.js' => '9f081f05', - 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'aa3a100c', - 'rsrc/js/application/repository/repository-crossreference.js' => '6337cf26', + 'rsrc/js/application/repository/repository-crossreference.js' => '44d48cd1', 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e5bdb730', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'b86f297f', 'rsrc/js/application/transactions/behavior-comment-actions.js' => '4dffaeb2', @@ -460,7 +454,8 @@ 'rsrc/js/core/DraggableList.js' => '0169e425', 'rsrc/js/core/Favicon.js' => '7930776a', 'rsrc/js/core/FileUpload.js' => 'ab85e184', - 'rsrc/js/core/Hovercard.js' => '074f0783', + 'rsrc/js/core/Hovercard.js' => '6199f752', + 'rsrc/js/core/HovercardList.js' => 'de4b4919', 'rsrc/js/core/KeyboardShortcut.js' => '1a844c06', 'rsrc/js/core/KeyboardShortcutManager.js' => '81debc48', 'rsrc/js/core/MultirowRowManager.js' => '5b54c823', @@ -478,17 +473,17 @@ 'rsrc/js/core/behavior-copy.js' => 'cf32921f', 'rsrc/js/core/behavior-detect-timezone.js' => '78bc5d94', 'rsrc/js/core/behavior-device.js' => 'ac2b1e01', - 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '7ad020a5', - 'rsrc/js/core/behavior-fancy-datepicker.js' => '956f3eeb', + 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '3277c62d', + 'rsrc/js/core/behavior-fancy-datepicker.js' => '36821f8d', 'rsrc/js/core/behavior-form.js' => '55d7b788', 'rsrc/js/core/behavior-gesture.js' => 'b58d1a2a', 'rsrc/js/core/behavior-global-drag-and-drop.js' => '1cab0e9a', 'rsrc/js/core/behavior-high-security-warning.js' => 'dae2d55b', 'rsrc/js/core/behavior-history-install.js' => '6a1583a8', - 'rsrc/js/core/behavior-hovercard.js' => '6c379000', + 'rsrc/js/core/behavior-hovercard.js' => '183738e6', 'rsrc/js/core/behavior-keyboard-pager.js' => '1325b731', 'rsrc/js/core/behavior-keyboard-shortcuts.js' => '42c44e8b', - 'rsrc/js/core/behavior-lightbox-attachments.js' => 'c7e748bf', + 'rsrc/js/core/behavior-lightbox-attachments.js' => '14c7ab36', 'rsrc/js/core/behavior-line-linker.js' => '0d915ff5', 'rsrc/js/core/behavior-linked-container.js' => '74446546', 'rsrc/js/core/behavior-more.js' => '506aa3f4', @@ -568,7 +563,7 @@ 'differential-core-view-css' => '7300a73e', 'differential-revision-add-comment-css' => '7e5900d9', 'differential-revision-comment-css' => '7dbc8d1d', - 'differential-revision-history-css' => '8aa3eac5', + 'differential-revision-history-css' => '237a2979', 'differential-revision-list-css' => '93d2df7d', 'differential-table-of-contents-css' => 'bba788b9', 'diffusion-css' => 'e46232d6', @@ -586,7 +581,7 @@ 'harbormaster-css' => '8dfe16b2', 'herald-css' => '648d39e2', 'herald-rule-editor' => '2633bef7', - 'herald-test-css' => 'e004176f', + 'herald-test-css' => '7e7bbdae', 'inline-comment-summary-css' => '81eb368d', 'javelin-aphlict' => '022516b4', 'javelin-behavior' => '1b6acc2a', @@ -594,7 +589,7 @@ 'javelin-behavior-aphlict-listen' => '4e61fa88', 'javelin-behavior-aphlict-status' => 'c3703a16', 'javelin-behavior-aphront-basic-tokenizer' => '3b4899b0', - 'javelin-behavior-aphront-drag-and-drop-textarea' => '7ad020a5', + 'javelin-behavior-aphront-drag-and-drop-textarea' => '3277c62d', 'javelin-behavior-aphront-form-disable-on-submit' => '55d7b788', 'javelin-behavior-aphront-more' => '506aa3f4', 'javelin-behavior-audio-source' => '3dc5ad43', @@ -623,7 +618,7 @@ 'javelin-behavior-differential-diff-radios' => '925fe8cd', 'javelin-behavior-differential-populate' => 'b86ef6c2', 'javelin-behavior-diffusion-commit-branches' => '4b671572', - 'javelin-behavior-diffusion-commit-graph' => '3be6ef4f', + 'javelin-behavior-diffusion-commit-graph' => 'ac10c917', 'javelin-behavior-diffusion-locate-file' => '87428eb2', 'javelin-behavior-diffusion-pull-lastmodified' => 'c715c123', 'javelin-behavior-document-engine' => '243d6c22', @@ -633,7 +628,7 @@ 'javelin-behavior-editengine-reorder-configs' => '4842f137', 'javelin-behavior-editengine-reorder-fields' => '0ad8d31f', 'javelin-behavior-event-all-day' => '0b1bc990', - 'javelin-behavior-fancy-datepicker' => '956f3eeb', + 'javelin-behavior-fancy-datepicker' => '36821f8d', 'javelin-behavior-global-drag-and-drop' => '1cab0e9a', 'javelin-behavior-harbormaster-log' => 'b347a301', 'javelin-behavior-herald-rule-editor' => '0922e81d', @@ -641,7 +636,7 @@ 'javelin-behavior-history-install' => '6a1583a8', 'javelin-behavior-icon-composer' => '38a6cedb', 'javelin-behavior-launch-icon-composer' => 'a17b84f1', - 'javelin-behavior-lightbox-attachments' => 'c7e748bf', + 'javelin-behavior-lightbox-attachments' => '14c7ab36', 'javelin-behavior-line-chart' => 'ad258e28', 'javelin-behavior-linked-container' => '74446546', 'javelin-behavior-maniphest-batch-selector' => '139ef688', @@ -670,7 +665,7 @@ 'javelin-behavior-pholio-mock-view' => '5aa1544e', 'javelin-behavior-phui-dropdown-menu' => '5cf0501a', 'javelin-behavior-phui-file-upload' => 'e150bd50', - 'javelin-behavior-phui-hovercards' => '6c379000', + 'javelin-behavior-phui-hovercards' => '183738e6', 'javelin-behavior-phui-selectable-list' => 'b26a41e4', 'javelin-behavior-phui-submenu' => 'b5e9bff9', 'javelin-behavior-phui-tab-group' => '242aa08b', @@ -684,15 +679,12 @@ 'javelin-behavior-read-only-warning' => 'b9109f8f', 'javelin-behavior-redirect' => '407ee861', 'javelin-behavior-refresh-csrf' => '46116c01', - 'javelin-behavior-releeph-preview-branch' => '75184d68', - 'javelin-behavior-releeph-request-state-change' => '9f081f05', - 'javelin-behavior-releeph-request-typeahead' => 'aa3a100c', 'javelin-behavior-remarkup-load-image' => '202bfa3f', 'javelin-behavior-remarkup-preview' => 'd8a86cfb', 'javelin-behavior-reorder-applications' => 'aa371860', 'javelin-behavior-reorder-columns' => '8ac32fd9', 'javelin-behavior-reorder-profile-menu-items' => 'e5bdb730', - 'javelin-behavior-repository-crossreference' => '6337cf26', + 'javelin-behavior-repository-crossreference' => '44d48cd1', 'javelin-behavior-scrollbar' => '92388bae', 'javelin-behavior-search-reorder-queries' => 'b86f297f', 'javelin-behavior-select-content' => 'e8240b50', @@ -715,7 +707,7 @@ 'javelin-color' => '78f811c9', 'javelin-cookie' => '05d290ef', 'javelin-diffusion-locate-file-source' => '94243d89', - 'javelin-dom' => '94681e22', + 'javelin-dom' => 'e4c7622a', 'javelin-dynval' => '202a2e85', 'javelin-event' => 'c03f2fb4', 'javelin-external-editor-link-engine' => '48a8641f', @@ -732,7 +724,7 @@ 'javelin-reactor-node-calmer' => '225bbb98', 'javelin-reactornode' => '72960bc1', 'javelin-request' => '84e6891f', - 'javelin-resource' => '740956e1', + 'javelin-resource' => '20514cc2', 'javelin-routable' => '6a18c42e', 'javelin-router' => '32755edb', 'javelin-scrollbar' => 'a43ae2ae', @@ -784,9 +776,10 @@ 'phabricator-darklog' => '3b869402', 'phabricator-darkmessage' => '26cd4b73', 'phabricator-dashboard-css' => '5a205b9d', - 'phabricator-diff-changeset' => '39dcf2c3', + 'phabricator-diff-changeset' => 'd7d3ba75', 'phabricator-diff-changeset-list' => 'cc2c5de5', - 'phabricator-diff-inline' => '511a1315', + 'phabricator-diff-inline' => '9c775532', + 'phabricator-diff-inline-content-state' => 'aa51efb4', 'phabricator-diff-path-view' => '8207abf9', 'phabricator-diff-tree-view' => '5d83623b', 'phabricator-drag-and-drop-file-upload' => '4370900d', @@ -806,7 +799,7 @@ 'phabricator-object-selector-css' => 'ee77366f', 'phabricator-phtize' => '2f1db1ed', 'phabricator-prefab' => '5793d835', - 'phabricator-remarkup-css' => '94c3d777', + 'phabricator-remarkup-css' => '5baa3bd9', 'phabricator-search-results-css' => '9ea70ace', 'phabricator-shaped-request' => '995f5102', 'phabricator-slowvote-css' => '1694baed', @@ -845,7 +838,7 @@ 'phui-comment-form-css' => '68a2d99a', 'phui-comment-panel-css' => 'ec4e31c0', 'phui-crumbs-view-css' => '614f43cf', - 'phui-curtain-object-ref-view-css' => '12404744', + 'phui-curtain-object-ref-view-css' => '51d93266', 'phui-curtain-view-css' => '68c5efb6', 'phui-document-summary-view-css' => 'b068eed1', 'phui-document-view-css' => '52b748a5', @@ -858,7 +851,8 @@ 'phui-formation-view-css' => 'd2dec8ed', 'phui-head-thing-view-css' => 'd7f293df', 'phui-header-view-css' => '36c86a58', - 'phui-hovercard' => '074f0783', + 'phui-hovercard' => '6199f752', + 'phui-hovercard-list' => 'de4b4919', 'phui-hovercard-view-css' => '6ca90fa0', 'phui-icon-set-selector-css' => '7aa5f3ec', 'phui-icon-view-css' => '4cbc684a', @@ -868,7 +862,7 @@ 'phui-invisible-character-view-css' => 'c694c4a4', 'phui-left-right-css' => '68513c34', 'phui-lightbox-css' => '4ebf22da', - 'phui-list-view-css' => '2f253c22', + 'phui-list-view-css' => '0c04affd', 'phui-object-box-css' => 'b8d7eea0', 'phui-oi-big-ui-css' => 'fa74cc35', 'phui-oi-color-css' => 'b517bfa0', @@ -883,8 +877,8 @@ 'phui-remarkup-preview-css' => '91767007', 'phui-segment-bar-view-css' => '5166b370', 'phui-spacing-css' => 'b05cadc3', - 'phui-status-list-view-css' => 'e5ff8be0', - 'phui-tag-view-css' => '8519160a', + 'phui-status-list-view-css' => '293b5dad', + 'phui-tag-view-css' => 'fb811341', 'phui-theme-css' => '35883b37', 'phui-timeline-view-css' => '2d32d7a9', 'phui-two-column-view-css' => 'f96d319f', @@ -906,13 +900,9 @@ 'policy-edit-css' => '8794e2ed', 'policy-transaction-detail-css' => 'c02b8384', 'ponder-view-css' => '05a09d0a', - 'project-card-view-css' => '4e7371cd', + 'project-card-view-css' => 'a9f2c2dd', 'project-triggers-css' => 'cd9c8bb9', 'project-view-css' => '567858b3', - 'releeph-core' => 'f81ff2db', - 'releeph-preview-branch' => '22db5c07', - 'releeph-request-differential-create-dialog' => '0ac1ea31', - 'releeph-request-typeahead-css' => 'bce37359', 'setup-issue-css' => '5eed85b2', 'sprite-login-css' => '18b368a6', 'sprite-tokens-css' => 'f1896dc5', @@ -986,13 +976,6 @@ 'javelin-uri', 'phabricator-notification', ), - '074f0783' => array( - 'javelin-install', - 'javelin-dom', - 'javelin-vector', - 'javelin-request', - 'javelin-uri', - ), '0889b835' => array( 'javelin-install', 'javelin-event', @@ -1044,6 +1027,23 @@ 'javelin-stratcom', 'javelin-util', ), + '14c7ab36' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'javelin-mask', + 'javelin-util', + 'phuix-icon-view', + 'phabricator-busy', + ), + '183738e6' => array( + 'javelin-behavior', + 'javelin-behavior-device', + 'javelin-stratcom', + 'javelin-vector', + 'phui-hovercard', + 'phui-hovercard-list', + ), '1a844c06' => array( 'javelin-install', 'javelin-util', @@ -1092,6 +1092,11 @@ 'javelin-behavior', 'javelin-request', ), + '20514cc2' => array( + 'javelin-util', + 'javelin-uri', + 'javelin-install', + ), '225bbb98' => array( 'javelin-install', 'javelin-reactor', @@ -1190,6 +1195,13 @@ 'javelin-install', 'javelin-util', ), + '3277c62d' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-json', + 'phabricator-drag-and-drop-file-upload', + 'phabricator-textareautils', + ), '32db8374' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1210,6 +1222,13 @@ 'aphront-typeahead-control-css', 'phui-tag-view-css', ), + '36821f8d' => array( + 'javelin-behavior', + 'javelin-util', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-vector', + ), '3829a3cf' => array( 'javelin-behavior', 'javelin-uri', @@ -1229,20 +1248,6 @@ 'trigger-rule', 'trigger-rule-type', ), - '39dcf2c3' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'javelin-router', - 'javelin-behavior-device', - 'javelin-vector', - 'phabricator-diff-inline', - 'phabricator-diff-path-view', - 'phuix-button-view', - 'javelin-external-editor-link-engine', - ), '3ae89b20' => array( 'phui-workcard-view-css', ), @@ -1250,11 +1255,6 @@ 'javelin-behavior', 'phabricator-prefab', ), - '3be6ef4f' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - ), '3dc5ad43' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1302,6 +1302,12 @@ '43bc9360' => array( 'javelin-install', ), + '44d48cd1' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-uri', + ), '457f4d16' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1400,9 +1406,6 @@ 'javelin-stratcom', 'javelin-dom', ), - '511a1315' => array( - 'javelin-dom', - ), '5202e831' => array( 'javelin-install', 'javelin-dom', @@ -1522,10 +1525,11 @@ '60cd9241' => array( 'javelin-behavior', ), - '6337cf26' => array( - 'javelin-behavior', + '6199f752' => array( + 'javelin-install', 'javelin-dom', - 'javelin-stratcom', + 'javelin-vector', + 'javelin-request', 'javelin-uri', ), '65bb0011' => array( @@ -1562,13 +1566,6 @@ 'javelin-workflow', 'javelin-magical-init', ), - '6c379000' => array( - 'javelin-behavior', - 'javelin-behavior-device', - 'javelin-stratcom', - 'javelin-vector', - 'phui-hovercard', - ), '6cfa0008' => array( 'javelin-dom', 'javelin-dynval', @@ -1598,21 +1595,10 @@ 'javelin-stratcom', 'phabricator-tooltip', ), - '740956e1' => array( - 'javelin-util', - 'javelin-uri', - 'javelin-install', - ), 74446546 => array( 'javelin-behavior', 'javelin-dom', ), - '75184d68' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-uri', - 'javelin-request', - ), '78bc5d94' => array( 'javelin-behavior', 'javelin-uri', @@ -1625,12 +1611,6 @@ 'javelin-install', 'javelin-dom', ), - '7ad020a5' => array( - 'javelin-behavior', - 'javelin-dom', - 'phabricator-drag-and-drop-file-upload', - 'phabricator-textareautils', - ), '7b139193' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1782,20 +1762,6 @@ 'javelin-uri', 'javelin-routable', ), - '94681e22' => array( - 'javelin-magical-init', - 'javelin-install', - 'javelin-util', - 'javelin-vector', - 'javelin-stratcom', - ), - '956f3eeb' => array( - 'javelin-behavior', - 'javelin-util', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-vector', - ), '9623adc1' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1824,6 +1790,10 @@ 'javelin-dom', 'javelin-workflow', ), + '9c775532' => array( + 'javelin-dom', + 'phabricator-diff-inline-content-state', + ), '9cec214e' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1832,14 +1802,6 @@ 'javelin-uri', 'phabricator-textareautils', ), - '9f081f05' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-workflow', - 'javelin-util', - 'phabricator-keyboard-shortcut', - ), 'a17b84f1' => array( 'javelin-behavior', 'javelin-dom', @@ -1907,11 +1869,7 @@ 'javelin-dom', 'phabricator-draggable-list', ), - 'aa3a100c' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-typeahead', - 'javelin-typeahead-ondemand-source', + 'aa51efb4' => array( 'javelin-dom', ), 'aa6d2308' => array( @@ -1927,6 +1885,11 @@ 'javelin-dom', 'phabricator-notification', ), + 'ac10c917' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + ), 'ac2b1e01' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2088,15 +2051,6 @@ 'javelin-workflow', 'javelin-json', ), - 'c7e748bf' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'javelin-mask', - 'javelin-util', - 'phuix-icon-view', - 'phabricator-busy', - ), 'cc2c5de5' => array( 'javelin-install', 'phuix-button-view', @@ -2126,6 +2080,20 @@ 'd4cc2d2a' => array( 'javelin-install', ), + 'd7d3ba75' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + 'javelin-router', + 'javelin-behavior-device', + 'javelin-vector', + 'phabricator-diff-inline', + 'phabricator-diff-path-view', + 'phuix-button-view', + 'javelin-external-editor-link-engine', + ), 'd8a86cfb' => array( 'javelin-behavior', 'javelin-dom', @@ -2144,12 +2112,27 @@ 'javelin-uri', 'phabricator-notification', ), + 'de4b4919' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-vector', + 'javelin-request', + 'javelin-uri', + 'phui-hovercard', + ), 'e150bd50' => array( 'javelin-behavior', 'javelin-stratcom', 'javelin-dom', 'phuix-dropdown-menu', ), + 'e4c7622a' => array( + 'javelin-magical-init', + 'javelin-install', + 'javelin-util', + 'javelin-vector', + 'javelin-stratcom', + ), 'e5bdb730' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2367,6 +2350,7 @@ 'javelin-behavior-global-drag-and-drop', 'javelin-behavior-phabricator-reveal-content', 'phui-hovercard', + 'phui-hovercard-list', 'javelin-behavior-phui-hovercards', 'javelin-color', 'javelin-fx', @@ -2429,6 +2413,7 @@ 'javelin-behavior-phabricator-object-selector', 'javelin-behavior-repository-crossreference', 'javelin-behavior-aphront-more', + 'phabricator-diff-inline-content-state', 'phabricator-diff-inline', 'phabricator-diff-changeset', 'phabricator-diff-changeset-list', diff -Nru phabricator-0~git20200925/phabricator/resources/celerity/packages.php phabricator-0~git20220903/phabricator/resources/celerity/packages.php --- phabricator-0~git20200925/phabricator/resources/celerity/packages.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/celerity/packages.php 2022-06-14 16:29:55.000000000 +0000 @@ -60,6 +60,7 @@ 'javelin-behavior-global-drag-and-drop', 'javelin-behavior-phabricator-reveal-content', 'phui-hovercard', + 'phui-hovercard-list', 'javelin-behavior-phui-hovercards', 'javelin-color', 'javelin-fx', @@ -211,6 +212,7 @@ 'javelin-behavior-aphront-more', + 'phabricator-diff-inline-content-state', 'phabricator-diff-inline', 'phabricator-diff-changeset', 'phabricator-diff-changeset-list', Binary files /tmp/tmp_740rqdz/4JQRZZA1RJ/phabricator-0~git20200925/phabricator/resources/sprite/login_1x/MediaWiki.png and /tmp/tmp_740rqdz/qZTn1pwj2f/phabricator-0~git20220903/phabricator/resources/sprite/login_1x/MediaWiki.png differ Binary files /tmp/tmp_740rqdz/4JQRZZA1RJ/phabricator-0~git20200925/phabricator/resources/sprite/login_2x/MediaWiki.png and /tmp/tmp_740rqdz/qZTn1pwj2f/phabricator-0~git20220903/phabricator/resources/sprite/login_2x/MediaWiki.png differ diff -Nru phabricator-0~git20200925/phabricator/resources/sprite/manifest/login.json phabricator-0~git20220903/phabricator/resources/sprite/manifest/login.json --- phabricator-0~git20200925/phabricator/resources/sprite/manifest/login.json 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sprite/manifest/login.json 2022-06-14 16:29:55.000000000 +0000 @@ -59,7 +59,7 @@ "login-MediaWiki": { "name": "login-MediaWiki", "rule": ".login-MediaWiki", - "hash": "f1f0a9382434081a9a84e7584828c2dd" + "hash": "68eba44e85ea942ecf14d3c08992a2e2" }, "login-PayPal": { "name": "login-PayPal", diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20140904.macroattach.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20140904.macroattach.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20140904.macroattach.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20140904.macroattach.php 2022-06-14 16:29:55.000000000 +0000 @@ -16,7 +16,7 @@ foreach ($phids as $phid) { $editor->addEdge( $macro->getPHID(), - PhabricatorObjectHasFileEdgeType::EDGECONST, + 25, $phid); } $editor->save(); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20190412.dashboard.13.rebuild.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20190412.dashboard.13.rebuild.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20190412.dashboard.13.rebuild.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20190412.dashboard.13.rebuild.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,5 +1,7 @@ <?php +// @phase worker + PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery( 'PhabricatorDashboardQuery'); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20190412.herald.01.rebuild.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20190412.herald.01.rebuild.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20190412.herald.01.rebuild.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20190412.herald.01.rebuild.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,3 +1,5 @@ <?php +// @phase worker + PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery('HeraldRuleQuery'); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20190909.herald.01.rebuild.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20190909.herald.01.rebuild.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20190909.herald.01.rebuild.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20190909.herald.01.rebuild.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,3 +1,5 @@ <?php +// @phase worker + PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery('HeraldRuleQuery'); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20191028.uriindex.01.rebuild.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20191028.uriindex.01.rebuild.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20191028.uriindex.01.rebuild.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20191028.uriindex.01.rebuild.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,4 +1,6 @@ <?php +// @phase worker + PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery( 'PhabricatorRepositoryQuery'); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210122.queuecontainer.01.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210122.queuecontainer.01.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210122.queuecontainer.01.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210122.queuecontainer.01.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,5 @@ +ALTER TABLE {$NAMESPACE}_worker.worker_activetask + ADD containerPHID VARBINARY(64); + +ALTER TABLE {$NAMESPACE}_worker.worker_archivetask + ADD containerPHID VARBINARY(64); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210215.changeset.01.phid.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210215.changeset.01.phid.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210215.changeset.01.phid.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210215.changeset.01.phid.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_differential.differential_changeset + ADD phid VARBINARY(64) NOT NULL; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210215.changeset.02.phid-populate.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210215.changeset.02.phid-populate.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210215.changeset.02.phid-populate.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210215.changeset.02.phid-populate.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,79 @@ +<?php + +$phid_type = DifferentialChangesetPHIDType::TYPECONST; + +$changeset_table = new DifferentialChangeset(); + +$conn = $changeset_table->establishConnection('w'); +$table_name = $changeset_table->getTableName(); + +$chunk_size = 4096; + +$temporary_table = 'tmp_20210215_changeset_id_map'; + +try { + queryfx( + $conn, + 'CREATE TEMPORARY TABLE %T ( + changeset_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + changeset_phid VARBINARY(64) NOT NULL)', + $temporary_table); +} catch (AphrontAccessDeniedQueryException $ex) { + throw new PhutilProxyException( + pht( + 'Failed to "CREATE TEMPORARY TABLE". You may need to "GRANT" the '. + 'current MySQL user this permission.'), + $ex); +} + +$table_iterator = id(new LiskRawMigrationIterator($conn, $table_name)) + ->setPageSize($chunk_size); + +$chunk_iterator = new PhutilChunkedIterator($table_iterator, $chunk_size); +foreach ($chunk_iterator as $chunk) { + + $map = array(); + foreach ($chunk as $changeset_row) { + $phid = $changeset_row['phid']; + + if (strlen($phid)) { + continue; + } + + $phid = PhabricatorPHID::generateNewPHID($phid_type); + $id = $changeset_row['id']; + + $map[(int)$id] = $phid; + } + + if (!$map) { + continue; + } + + $sql = array(); + foreach ($map as $changeset_id => $changeset_phid) { + $sql[] = qsprintf( + $conn, + '(%d, %s)', + $changeset_id, + $changeset_phid); + } + + queryfx( + $conn, + 'TRUNCATE TABLE %T', + $temporary_table); + + queryfx( + $conn, + 'INSERT INTO %T (changeset_id, changeset_phid) VALUES %LQ', + $temporary_table, + $sql); + + queryfx( + $conn, + 'UPDATE %T c JOIN %T x ON c.id = x.changeset_id + SET c.phid = x.changeset_phid', + $table_name, + $temporary_table); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210216.index.01.version.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210216.index.01.version.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210216.index.01.version.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210216.index.01.version.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_search.search_indexversion + ADD indexVersion BINARY(12) NOT NULL; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210216.index.02.epoch.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210216.index.02.epoch.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210216.index.02.epoch.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210216.index.02.epoch.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_search.search_indexversion + ADD indexEpoch INT UNSIGNED NOT NULL; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210309.auditors.01.status.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210309.auditors.01.status.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210309.auditors.01.status.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210309.auditors.01.status.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,5 @@ +UPDATE {$NAMESPACE}_repository.repository_auditrequest + SET auditStatus = 'accepted' WHERE auditStatus = 'closed'; + +DELETE FROM {$NAMESPACE}_repository.repository_auditrequest + WHERE auditStatus IN ('', 'cc', 'audit-not-required'); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210315.affectedpath.01.epoch.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210315.affectedpath.01.epoch.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210315.affectedpath.01.epoch.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210315.affectedpath.01.epoch.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_differential.differential_affectedpath + DROP epoch; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210315.affectedpath.02.repositoryid.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210315.affectedpath.02.repositoryid.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210315.affectedpath.02.repositoryid.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210315.affectedpath.02.repositoryid.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_differential.differential_affectedpath + CHANGE repositoryID repositoryID INT UNSIGNED; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.01.device-mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.01.device-mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.01.device-mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.01.device-mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$device_table = new AlmanacDevice(); +$device_conn = $device_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $device_conn, + $device_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.02.device-dropmailkey.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.02.device-dropmailkey.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.02.device-dropmailkey.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.02.device-dropmailkey.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_almanac.almanac_device + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.03.device-status.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.03.device-status.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.03.device-status.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.03.device-status.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_almanac.almanac_device + ADD status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.04.device-status-value.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.04.device-status-value.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.04.device-status-value.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.04.device-status-value.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +UPDATE {$NAMESPACE}_almanac.almanac_device + SET status = 'active' WHERE status = ''; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.05.service-mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.05.service-mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.05.service-mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.05.service-mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$service_table = new AlmanacService(); +$service_conn = $service_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $service_conn, + $service_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.06.service-dropmailkey.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.06.service-dropmailkey.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.06.service-dropmailkey.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.06.service-dropmailkey.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_almanac.almanac_service + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.07.binding-mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.07.binding-mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.07.binding-mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.07.binding-mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$binding_table = new AlmanacBinding(); +$binding_conn = $binding_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $binding_conn, + $binding_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.08.binding-dropmailkey.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.08.binding-dropmailkey.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.08.binding-dropmailkey.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.08.binding-dropmailkey.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_almanac.almanac_binding + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.09.namespace-mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.09.namespace-mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.09.namespace-mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.09.namespace-mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$namespace_table = new AlmanacNamespace(); +$namespace_conn = $namespace_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $namespace_conn, + $namespace_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.10.namespace-dropmailkey.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.10.namespace-dropmailkey.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.10.namespace-dropmailkey.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.10.namespace-dropmailkey.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_almanac.almanac_namespace + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.11.network-mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.11.network-mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.11.network-mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.11.network-mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$network_table = new AlmanacNetwork(); +$network_conn = $network_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $network_conn, + $network_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.12.network-dropmailkey.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.12.network-dropmailkey.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.12.network-dropmailkey.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.12.network-dropmailkey.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_almanac.almanac_network + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.13.event-mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.13.event-mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.13.event-mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.13.event-mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$event_table = new PhabricatorCalendarEvent(); +$event_conn = $event_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $event_conn, + $event_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.14.event-dropmailkey.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.14.event-dropmailkey.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.14.event-dropmailkey.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.14.event-dropmailkey.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_calendar.calendar_event + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.15.intiative-mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.15.intiative-mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.15.intiative-mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.15.intiative-mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$initiative_table = new FundInitiative(); +$initiative_conn = $initiative_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $initiative_conn, + $initiative_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.16.initiative-dropmailkey.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.16.initiative-dropmailkey.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210316.almanac.16.initiative-dropmailkey.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210316.almanac.16.initiative-dropmailkey.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_fund.fund_initiative + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210625.owners.01.authority.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210625.owners.01.authority.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210625.owners.01.authority.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210625.owners.01.authority.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_owners.owners_package + ADD authorityMode VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210625.owners.02.authority-default.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210625.owners.02.authority-default.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210625.owners.02.authority-default.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210625.owners.02.authority-default.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,3 @@ +UPDATE {$NAMESPACE}_owners.owners_package + SET authorityMode = 'strong' + WHERE authorityMode = ''; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210713.harborcommand.01.migrate.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210713.harborcommand.01.migrate.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210713.harborcommand.01.migrate.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210713.harborcommand.01.migrate.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,4 @@ +INSERT IGNORE INTO {$NAMESPACE}_harbormaster.harbormaster_buildmessage + (authorPHID, receiverPHID, type, isConsumed, dateCreated, dateModified) + SELECT authorPHID, targetPHID, command, 0, dateCreated, dateModified + FROM {$NAMESPACE}_harbormaster.harbormaster_buildcommand; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210713.harborcommand.02.drop.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210713.harborcommand.02.drop.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210713.harborcommand.02.drop.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210713.harborcommand.02.drop.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1 @@ +DROP TABLE IF EXISTS {$NAMESPACE}_harbormaster.harbormaster_buildcommand; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210715.harborcommand.01.xactions.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210715.harborcommand.01.xactions.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20210715.harborcommand.01.xactions.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20210715.harborcommand.01.xactions.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,34 @@ +<?php + +// See T13072. Turn the old "process a command" transaction into modular +// transactions that each handle one particular type of command. + +$xactions_table = new HarbormasterBuildTransaction(); +$xactions_conn = $xactions_table->establishConnection('w'); +$row_iterator = new LiskRawMigrationIterator( + $xactions_conn, + $xactions_table->getTableName()); + +$map = array( + '"pause"' => 'message/pause', + '"abort"' => 'message/abort', + '"resume"' => 'message/resume', + '"restart"' => 'message/restart', +); + +foreach ($row_iterator as $row) { + if ($row['transactionType'] !== 'harbormaster:build:command') { + continue; + } + + $raw_value = $row['newValue']; + + if (isset($map[$raw_value])) { + queryfx( + $xactions_conn, + 'UPDATE %R SET transactionType = %s WHERE id = %d', + $xactions_table, + $map[$raw_value], + $row['id']); + } +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.01.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.01.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.01.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.01.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,5 @@ +UPDATE {$NAMESPACE}_phame.phame_blog + SET editPolicy = 'admin' WHERE editPolicy IS NULL; + +ALTER TABLE {$NAMESPACE}_phame.phame_blog + CHANGE editPolicy editPolicy VARBINARY(64) NOT NULL; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.02.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.02.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.02.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.02.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,5 @@ +UPDATE {$NAMESPACE}_phame.phame_blog + SET viewPolicy = 'admin' WHERE viewPolicy IS NULL; + +ALTER TABLE {$NAMESPACE}_phame.phame_blog + CHANGE viewPolicy viewPolicy VARBINARY(64) NOT NULL; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.03.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.03.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.03.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.03.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,6 @@ +ALTER TABLE {$NAMESPACE}_phame.phame_blog + ADD interactPolicy VARBINARY(64) NOT NULL; + +UPDATE {$NAMESPACE}_phame.phame_blog + SET interactPolicy = 'users' + WHERE interactPolicy = ''; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.04.postinteract.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.04.postinteract.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220401.phameinteract.04.postinteract.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220401.phameinteract.04.postinteract.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,6 @@ +ALTER TABLE {$NAMESPACE}_phame.phame_post + ADD interactPolicy VARBINARY(64) NOT NULL; + +UPDATE {$NAMESPACE}_phame.phame_post + SET interactPolicy = 'obj.phame.blog' + WHERE interactPolicy = ''; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220510.file.01.attach.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220510.file.01.attach.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220510.file.01.attach.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220510.file.01.attach.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_file.file_attachment ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + filePHID VARBINARY(64) NOT NULL, + attacherPHID VARBINARY(64), + attachmentMode VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220519.file.02.migrate.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220519.file.02.migrate.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220519.file.02.migrate.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220519.file.02.migrate.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,7 @@ +INSERT IGNORE INTO {$NAMESPACE}_file.file_attachment + (objectPHID, filePHID, attachmentMode, attacherPHID, + dateCreated, dateModified) + SELECT dst, src, 'attach', null, dateCreated, dateCreated + FROM {$NAMESPACE}_file.edge + WHERE type = 26 + ORDER BY dateCreated ASC; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.01.mailkey.php phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.01.mailkey.php --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.01.mailkey.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.01.mailkey.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,28 @@ +<?php + +$poll_table = new PhabricatorSlowvotePoll(); +$poll_conn = $poll_table->establishConnection('w'); + +$properties_table = new PhabricatorMetaMTAMailProperties(); +$conn = $properties_table->establishConnection('w'); + +$iterator = new LiskRawMigrationIterator( + $poll_conn, + $poll_table->getTableName()); + +foreach ($iterator as $row) { + queryfx( + $conn, + 'INSERT IGNORE INTO %R + (objectPHID, mailProperties, dateCreated, dateModified) + VALUES + (%s, %s, %d, %d)', + $properties_table, + $row['phid'], + phutil_json_encode( + array( + 'mailKey' => $row['mailKey'], + )), + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.02.mailkey-drop.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.02.mailkey-drop.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.02.mailkey-drop.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.02.mailkey-drop.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_slowvote.slowvote_poll + DROP mailKey; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.03.response-type.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.03.response-type.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.03.response-type.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.03.response-type.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,3 @@ +ALTER TABLE {$NAMESPACE}_slowvote.slowvote_poll + CHANGE responseVisibility + responseVisibility VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.04.response-value.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.04.response-value.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.04.response-value.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.04.response-value.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,8 @@ +UPDATE {$NAMESPACE}_slowvote.slowvote_poll + SET responseVisibility = 'visible' WHERE responseVisibility = '0'; + +UPDATE {$NAMESPACE}_slowvote.slowvote_poll + SET responseVisibility = 'voters' WHERE responseVisibility = '1'; + +UPDATE {$NAMESPACE}_slowvote.slowvote_poll + SET responseVisibility = 'owner' WHERE responseVisibility = '2'; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.05.response-xactions.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.05.response-xactions.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.05.response-xactions.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.05.response-xactions.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,23 @@ +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET oldValue = '"visible"' WHERE + transactionType = 'vote:responses' AND oldValue IN ('0', '"0"'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET newValue = '"visible"' WHERE + transactionType = 'vote:responses' AND newValue IN ('0', '"0"'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET oldValue = '"voters"' WHERE + transactionType = 'vote:responses' AND oldValue IN ('1', '"1"'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET newValue = '"voters"' WHERE + transactionType = 'vote:responses' AND newValue IN ('1', '"1"'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET oldValue = '"owner"' WHERE + transactionType = 'vote:responses' AND oldValue IN ('2', '"2"'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET newValue = '"owner"' WHERE + transactionType = 'vote:responses' AND newValue IN ('2', '"2"'); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.06.method-type.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.06.method-type.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.06.method-type.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.06.method-type.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_slowvote.slowvote_poll + CHANGE method method VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.07.method-value.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.07.method-value.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.07.method-value.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.07.method-value.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,5 @@ +UPDATE {$NAMESPACE}_slowvote.slowvote_poll + SET method = 'plurality' WHERE method = '0'; + +UPDATE {$NAMESPACE}_slowvote.slowvote_poll + SET method = 'approval' WHERE method = '1'; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.08.status-type.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.08.status-type.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.08.status-type.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.08.status-type.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_slowvote.slowvote_poll + CHANGE isClosed status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.09.status-value.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.09.status-value.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.09.status-value.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.09.status-value.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,5 @@ +UPDATE {$NAMESPACE}_slowvote.slowvote_poll + SET status = 'open' WHERE status = '0'; + +UPDATE {$NAMESPACE}_slowvote.slowvote_poll + SET status = 'closed' WHERE status = '1'; diff -Nru phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.10.status-xactions.sql phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.10.status-xactions.sql --- phabricator-0~git20200925/phabricator/resources/sql/autopatches/20220525.slowvote.10.status-xactions.sql 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/autopatches/20220525.slowvote.10.status-xactions.sql 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,19 @@ +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET transactionType = 'vote:status' + WHERE transactionType = 'vote:close'; + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET oldValue = '"open"' WHERE + transactionType = 'vote:status' AND oldValue IN ('0', '"0"', 'false'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET newValue = '"open"' WHERE + transactionType = 'vote:status' AND newValue IN ('0', '"0"', 'false'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET oldValue = '"closed"' WHERE + transactionType = 'vote:status' AND oldValue IN ('1', '"1"', 'true'); + +UPDATE {$NAMESPACE}_slowvote.slowvote_transaction + SET newValue = '"closed"' WHERE + transactionType = 'vote:status' AND newValue IN ('1', '"1"', 'true'); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/patches/20130611.migrateoauth.php phabricator-0~git20220903/phabricator/resources/sql/patches/20130611.migrateoauth.php --- phabricator-0~git20200925/phabricator/resources/sql/patches/20130611.migrateoauth.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/patches/20130611.migrateoauth.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,8 +7,8 @@ foreach (new LiskRawMigrationIterator($conn, $table_name) as $row) { throw new Exception( pht( - 'Your Phabricator install has ancient OAuth account data and is '. - 'too old to upgrade directly to a modern version of Phabricator. '. - 'Upgrade to a version released between June 2013 and February 2019 '. - 'first, then upgrade to a modern version.')); + 'This database has ancient OAuth account data and is too old to '. + 'upgrade directly to a modern software version. Upgrade to a version '. + 'released between June 2013 and February 2019 first, then upgrade to '. + 'a modern version.')); } diff -Nru phabricator-0~git20200925/phabricator/resources/sql/patches/20130611.nukeldap.php phabricator-0~git20220903/phabricator/resources/sql/patches/20130611.nukeldap.php --- phabricator-0~git20200925/phabricator/resources/sql/patches/20130611.nukeldap.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/patches/20130611.nukeldap.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,8 +7,8 @@ foreach (new LiskRawMigrationIterator($conn, $table_name) as $row) { throw new Exception( pht( - 'Your Phabricator install has ancient LDAP account data and is '. - 'too old to upgrade directly to a modern version of Phabricator. '. - 'Upgrade to a version released between June 2013 and February 2019 '. - 'first, then upgrade to a modern version.')); + 'This database has ancient LDAP account data and is too old to upgrade '. + 'directly to a modern version of the software. Upgrade to a version '. + 'released between June 2013 and February 2019 first, then upgrade to a '. + 'modern version.')); } diff -Nru phabricator-0~git20200925/phabricator/resources/sql/patches/20130820.file-mailkey-populate.php phabricator-0~git20220903/phabricator/resources/sql/patches/20130820.file-mailkey-populate.php --- phabricator-0~git20200925/phabricator/resources/sql/patches/20130820.file-mailkey-populate.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/patches/20130820.file-mailkey-populate.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,6 @@ <?php -echo pht('Populating Phabricator files with mail keys xactions...')."\n"; +echo pht('Populating files with mail keys...')."\n"; $table = new PhabricatorFile(); $table_name = $table->getTableName(); diff -Nru phabricator-0~git20200925/phabricator/resources/sql/patches/20131004.dxreviewers.php phabricator-0~git20220903/phabricator/resources/sql/patches/20131004.dxreviewers.php --- phabricator-0~git20200925/phabricator/resources/sql/patches/20131004.dxreviewers.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/patches/20131004.dxreviewers.php 2022-06-14 16:29:55.000000000 +0000 @@ -29,8 +29,7 @@ foreach ($reviewer_phids as $dst) { if (phid_get_type($dst) == PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { // At least one old install ran into some issues here. Skip the row if we - // can't figure out what the destination PHID is. See here: - // https://github.com/phacility/phabricator/pull/507 + // can't figure out what the destination PHID is. continue; } diff -Nru phabricator-0~git20200925/phabricator/resources/sql/quickstart.sql phabricator-0~git20220903/phabricator/resources/sql/quickstart.sql --- phabricator-0~git20200925/phabricator/resources/sql/quickstart.sql 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/resources/sql/quickstart.sql 2022-06-14 16:29:55.000000000 +0000 @@ -7552,113 +7552,6 @@ KEY `key_merchant` (`merchantPHID`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; -CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_phragment` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; - -USE `{$NAMESPACE}_phragment`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `edge` ( - `src` varbinary(64) NOT NULL, - `type` int(10) unsigned NOT NULL, - `dst` varbinary(64) NOT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `seq` int(10) unsigned NOT NULL, - `dataID` int(10) unsigned DEFAULT NULL, - PRIMARY KEY (`src`,`type`,`dst`), - UNIQUE KEY `key_dst` (`dst`,`type`,`src`), - KEY `src` (`src`,`type`,`dateCreated`,`seq`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_phragment`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `edgedata` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `data` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_phragment`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `phragment_fragment` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `path` varchar(128) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `depth` int(10) unsigned NOT NULL, - `latestVersionPHID` varbinary(64) DEFAULT NULL, - `viewPolicy` varbinary(64) NOT NULL, - `editPolicy` varbinary(64) NOT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_phid` (`phid`), - UNIQUE KEY `key_path` (`path`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_phragment`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `phragment_fragmentversion` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `sequence` int(10) unsigned NOT NULL, - `fragmentPHID` varbinary(64) NOT NULL, - `filePHID` varbinary(64) DEFAULT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_version` (`fragmentPHID`,`sequence`), - UNIQUE KEY `key_phid` (`phid`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_phragment`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `phragment_snapshot` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `primaryFragmentPHID` varbinary(64) NOT NULL, - `name` varchar(128) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_phid` (`phid`), - UNIQUE KEY `key_name` (`primaryFragmentPHID`,`name`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_phragment`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `phragment_snapshotchild` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `snapshotPHID` varbinary(64) NOT NULL, - `fragmentPHID` varbinary(64) NOT NULL, - `fragmentVersionPHID` varbinary(64) DEFAULT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_child` (`snapshotPHID`,`fragmentPHID`,`fragmentVersionPHID`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_phrequent` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; USE `{$NAMESPACE}_phrequent`; @@ -8667,190 +8560,6 @@ UNIQUE KEY `key_trigger` (`triggerPHID`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; -CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_releeph` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; - -USE `{$NAMESPACE}_releeph`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `releeph_branch` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - `basename` varchar(64) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `releephProjectID` int(10) unsigned NOT NULL, - `createdByUserPHID` varbinary(64) NOT NULL, - `cutPointCommitPHID` varbinary(64) NOT NULL, - `isActive` tinyint(1) NOT NULL DEFAULT '1', - `symbolicName` varchar(64) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} DEFAULT NULL, - `details` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `phid` varbinary(64) NOT NULL, - `name` varchar(128) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `releephProjectID_2` (`releephProjectID`,`basename`), - UNIQUE KEY `releephProjectID_name` (`releephProjectID`,`name`), - UNIQUE KEY `key_phid` (`phid`), - UNIQUE KEY `releephProjectID` (`releephProjectID`,`symbolicName`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_releeph`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `releeph_branchtransaction` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `authorPHID` varbinary(64) NOT NULL, - `objectPHID` varbinary(64) NOT NULL, - `viewPolicy` varbinary(64) NOT NULL, - `editPolicy` varbinary(64) NOT NULL, - `commentPHID` varbinary(64) DEFAULT NULL, - `commentVersion` int(10) unsigned NOT NULL, - `transactionType` varchar(32) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `oldValue` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `newValue` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `contentSource` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `metadata` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_phid` (`phid`), - KEY `key_object` (`objectPHID`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_releeph`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `releeph_producttransaction` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `authorPHID` varbinary(64) NOT NULL, - `objectPHID` varbinary(64) NOT NULL, - `viewPolicy` varbinary(64) NOT NULL, - `editPolicy` varbinary(64) NOT NULL, - `commentPHID` varbinary(64) DEFAULT NULL, - `commentVersion` int(10) unsigned NOT NULL, - `transactionType` varchar(32) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `oldValue` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `newValue` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `contentSource` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `metadata` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_phid` (`phid`), - KEY `key_object` (`objectPHID`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_releeph`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `releeph_project` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - `phid` varbinary(64) NOT NULL, - `name` varchar(128) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `trunkBranch` varchar(255) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `repositoryPHID` varbinary(64) NOT NULL, - `createdByUserPHID` varbinary(64) NOT NULL, - `isActive` tinyint(1) NOT NULL DEFAULT '1', - `details` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `projectName` (`name`), - UNIQUE KEY `key_phid` (`phid`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_releeph`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `releeph_request` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - `phid` varbinary(64) NOT NULL, - `branchID` int(10) unsigned NOT NULL, - `requestUserPHID` varbinary(64) NOT NULL, - `requestCommitPHID` varbinary(64) DEFAULT NULL, - `commitIdentifier` varchar(40) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} DEFAULT NULL, - `commitPHID` varbinary(64) DEFAULT NULL, - `pickStatus` int(10) unsigned DEFAULT NULL, - `details` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `userIntents` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT}, - `inBranch` tinyint(1) NOT NULL DEFAULT '0', - `mailKey` binary(20) NOT NULL, - `requestedObjectPHID` varbinary(64) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `phid` (`phid`), - UNIQUE KEY `requestIdentifierBranch` (`requestCommitPHID`,`branchID`), - KEY `branchID` (`branchID`), - KEY `key_requestedObject` (`requestedObjectPHID`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_releeph`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `releeph_requesttransaction` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `authorPHID` varbinary(64) NOT NULL, - `objectPHID` varbinary(64) NOT NULL, - `viewPolicy` varbinary(64) NOT NULL, - `editPolicy` varbinary(64) NOT NULL, - `commentPHID` varbinary(64) DEFAULT NULL, - `commentVersion` int(10) unsigned NOT NULL, - `transactionType` varchar(32) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `oldValue` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `newValue` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `metadata` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `contentSource` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_phid` (`phid`), - KEY `key_object` (`objectPHID`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - -USE `{$NAMESPACE}_releeph`; - - SET NAMES utf8 ; - - SET character_set_client = {$CHARSET} ; - -CREATE TABLE `releeph_requesttransaction_comment` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `transactionPHID` varbinary(64) DEFAULT NULL, - `authorPHID` varbinary(64) NOT NULL, - `viewPolicy` varbinary(64) NOT NULL, - `editPolicy` varbinary(64) NOT NULL, - `commentVersion` int(10) unsigned NOT NULL, - `content` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `contentSource` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, - `isDeleted` tinyint(1) NOT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `key_phid` (`phid`), - UNIQUE KEY `key_version` (`transactionPHID`,`commentVersion`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_repository` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; USE `{$NAMESPACE}_repository`; diff -Nru phabricator-0~git20200925/phabricator/scripts/fpm/warmup.php phabricator-0~git20220903/phabricator/scripts/fpm/warmup.php --- phabricator-0~git20200925/phabricator/scripts/fpm/warmup.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/fpm/warmup.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -<?php - -/** - * NOTE: This is an ADVANCED feature that improves performance but adds a lot - * of complexity! This is only suitable for production servers because workers - * won't pick up changes between when they spawn and when they handle a request. - * - * Phabricator spends a significant portion of its runtime loading classes - * and functions, even with APC enabled. Since we have very rigidly-defined - * rules about what can go in a module (specifically: no side effects), it - * is safe to load all the libraries *before* we receive a request. - * - * Normally, SAPIs don't provide a way to do this, but with a patched PHP-FPM - * SAPI you can provide a warmup file that it will execute before a request - * is received. - * - * We're limited in what we can do here, since request information won't - * exist yet, but we can load class and function definitions, which is what - * we're really interested in. - * - * Once this file exists, the FCGI process will drop into its normal accept loop - * and eventually process a request. - */ -function __warmup__() { - $root = dirname(dirname(dirname(dirname(__FILE__)))); - require_once $root.'/libphutil/src/__phutil_library_init__.php'; - require_once $root.'/arcanist/src/__phutil_library_init__.php'; - require_once $root.'/phabricator/src/__phutil_library_init__.php'; - - // Load every symbol. We could possibly refine this -- we don't need to load - // every Controller, for instance. - $loader = new PhutilSymbolLoader(); - $loader->selectAndLoadSymbols(); - - define('__WARMUP__', true); -} - -__warmup__(); diff -Nru phabricator-0~git20200925/phabricator/scripts/install/install_rhel-derivs.sh phabricator-0~git20220903/phabricator/scripts/install/install_rhel-derivs.sh --- phabricator-0~git20200925/phabricator/scripts/install/install_rhel-derivs.sh 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/install/install_rhel-derivs.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -#!/bin/bash - -confirm() { - echo "Press RETURN to continue, or ^C to cancel."; - read -e ignored -} - -RHEL_VER_FILE="/etc/redhat-release" - -if [[ ! -f $RHEL_VER_FILE ]] -then - echo "It looks like you're not running a Red Hat-derived distribution." - echo "This script is intended to install Phabricator on RHEL-derived" - echo "distributions such as RHEL, Fedora, CentOS, and Scientific Linux." - echo "Proceed with caution." - confirm -fi - -echo "PHABRICATOR RED HAT DERIVATIVE INSTALLATION SCRIPT"; -echo "This script will install Phabricator and all of its core dependencies."; -echo "Run it from the directory you want to install into."; -echo - -RHEL_REGEX="release ([0-9]+)\." - -if [[ $(cat $RHEL_VER_FILE) =~ $RHEL_REGEX ]] -then - RHEL_MAJOR_VER=${BASH_REMATCH[1]} -else - echo "Ut oh, we were unable to determine your distribution's major" - echo "version number. Please make sure you're running 6.0+ before" - echo "proceeding." - confirm -fi - -if [[ $RHEL_MAJOR_VER < 6 && $RHEL_MAJOR_VER > 0 ]] -then - echo "** WARNING **" - echo "A major version less than 6 was detected. Because of this," - echo "several needed dependencies are not available via default repos." - echo "Specifically, RHEL 5 does not have a PEAR package for php53-*." - echo "We will attempt to install it manually, for APC. Please be careful." - confirm -fi - -echo "Phabricator will be installed to: $(pwd)."; -confirm - -echo "Testing sudo/root..." -if [[ $EUID -ne 0 ]] # Check if we're root. If we are, continue. -then - sudo true - SUDO="sudo" - if [[ $? -ne 0 ]] - then - echo "ERROR: You must be able to sudo to run this script, or run it as root."; - exit 1 - fi - -fi - -if [[ $RHEL_MAJOR_VER == 5 ]] -then - # RHEL 5's "php" package is actually 5.1. The "php53" package won't let us install php-pecl-apc. - # (it tries to pull in php 5.1 stuff) ... - yum repolist | grep -i epel - if [ $? -ne 0 ]; then - echo "It doesn't look like you have the EPEL repo enabled. We are to add it" - echo "for you, so that we can install git." - $SUDO rpm -Uvh https://download.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm - fi - YUMCOMMAND="$SUDO yum install httpd git php53 php53-cli php53-mysql php53-process php53-devel php53-gd gcc wget make pcre-devel mysql-server" -else - # RHEL 6+ defaults with php 5.3 - YUMCOMMAND="$SUDO yum install httpd git php php-cli php-mysql php-process php-devel php-gd php-pecl-apc php-pecl-json php-mbstring mysql-server" -fi - -echo "Dropping to yum to install dependencies..." -echo "Running: ${YUMCOMMAND}" -echo "Yum will prompt you with [Y/n] to continue installing." - -$YUMCOMMAND - -if [[ $? -ne 0 ]] -then - echo "The yum command failed. Please fix the errors and re-run this script." - exit 1 -fi - -if [[ $RHEL_MAJOR_VER == 5 ]] -then - # Now that we've ensured all the devel packages required for pecl/apc are there, let's - # set up PEAR, and install apc. - echo "Attempting to install PEAR" - wget https://pear.php.net/go-pear.phar - $SUDO php go-pear.phar && $SUDO pecl install apc -fi - -if [[ $? -ne 0 ]] -then - echo "The apc install failed. Continuing without APC, performance may be impacted." -fi - -pidof httpd 2>&1 > /dev/null -if [[ $? -eq 0 ]] -then - echo "If php was installed above, please run: /etc/init.d/httpd graceful" -else - echo "Please remember to start the httpd with: /etc/init.d/httpd start" -fi - -pidof mysqld 2>&1 > /dev/null -if [[ $? -ne 0 ]] -then - echo "Please remember to start the mysql server: /etc/init.d/mysqld start" -fi - -confirm - -if [[ ! -e libphutil ]] -then - git clone https://github.com/phacility/libphutil.git -else - (cd libphutil && git pull --rebase) -fi - -if [[ ! -e arcanist ]] -then - git clone https://github.com/phacility/arcanist.git -else - (cd arcanist && git pull --rebase) -fi - -if [[ ! -e phabricator ]] -then - git clone https://github.com/phacility/phabricator.git -else - (cd phabricator && git pull --rebase) -fi - -echo -echo -echo "Install probably worked mostly correctly. Continue with the 'Configuration Guide':"; -echo -echo " https://secure.phabricator.com/book/phabricator/article/configuration_guide/"; diff -Nru phabricator-0~git20200925/phabricator/scripts/install/install_ubuntu.sh phabricator-0~git20220903/phabricator/scripts/install/install_ubuntu.sh --- phabricator-0~git20200925/phabricator/scripts/install/install_ubuntu.sh 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/install/install_ubuntu.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -#!/bin/bash - -confirm() { - echo "Press RETURN to continue, or ^C to cancel."; - read -e ignored -} - -INSTALL_URI=" https://phurl.io/u/install" - -failed() { - echo - echo - echo "Installation has failed." - echo "Text above this message might be useful to understanding what exactly failed." - echo - echo "Please follow this guide to manually complete installation:" - echo - echo $INSTALL_URI - echo - echo "We apologize for the inconvenience." - exit 3 -} - -ISSUE=`cat /etc/issue` -if [[ $ISSUE != Ubuntu* ]] -then - echo "This script is intended for use on Ubuntu, but this system appears"; - echo "to be something else. Your results may vary."; - echo - confirm -fi - -echo "PHABRICATOR UBUNTU INSTALL SCRIPT"; -echo "This script will install Apache, Phabricator and its core dependencies."; -echo "Run it from the directory you want to install into."; -echo - -echo "Testing sudo..." -sudo true -if [ $? -ne 0 ] -then - echo "ERROR: You must be able to sudo to run this script."; - exit 1; -fi; - -echo 'Testing Ubuntu version...' - -VERSION=`lsb_release -rs` -MAJOR=`expr match "$VERSION" '\([0-9]*\)'` - -if [ "$MAJOR" -lt 16 ] -then - echo 'This script is intented to install on modern operating systems; Your ' - echo 'operating system is too old for this script.' - echo 'You can still install Phabricator manually - please consult the installation' - echo 'guide to see how:' - echo - echo $INSTALL_URI - echo - exit 2 -fi - -# Ubuntu 16.04 LTS only has php 7.0 in their repos, so they need this extra ppa. -# Ubuntu 17.4 and up have official 7.2 builds. -if [ "$MAJOR" -eq 16 ] -then - echo 'This version of Ubuntu requires additional resources in order to install' - echo 'and run Phabricator.' - echo 'We will now add a the following package repository to your system:' - echo ' https://launchpad.net/~ondrej/+archive/ubuntu/php' - echo - echo 'This repository is generally considered safe to use.' - confirm - - sudo add-apt-repository -y ppa:ondrej/php || failed -fi - -ROOT=`pwd` -echo "Phabricator will be installed to: ${ROOT}."; -confirm - -echo "Installing dependencies: git, apache, mysql, php..."; -echo -sudo apt-get -qq update -sudo apt-get install \ - git mysql-server apache2 libapache2-mod-php \ - php php-mysql php-gd php-curl php-apcu php-cli php-json php-mbstring \ - || failed - -echo "Enabling mod_rewrite in Apache..." -echo -sudo a2enmod rewrite || failed - -echo "Downloading Phabricator and dependencies..." -echo -if [ ! -e libphutil ] -then - git clone https://github.com/phacility/libphutil.git -else - (cd libphutil && git pull --rebase) -fi - -if [ ! -e arcanist ] -then - git clone https://github.com/phacility/arcanist.git -else - (cd arcanist && git pull --rebase) -fi - -if [ ! -e phabricator ] -then - git clone https://github.com/phacility/phabricator.git -else - (cd phabricator && git pull --rebase) -fi - -echo -echo -echo "Install probably worked mostly correctly. Continue with the 'Configuration Guide':"; -echo -echo " https://secure.phabricator.com/book/phabricator/article/configuration_guide/"; -echo -echo 'Next step is "Configuring Apache webserver".' diff -Nru phabricator-0~git20200925/phabricator/scripts/install/update_phabricator.sh phabricator-0~git20220903/phabricator/scripts/install/update_phabricator.sh --- phabricator-0~git20200925/phabricator/scripts/install/update_phabricator.sh 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/install/update_phabricator.sh 2022-06-14 16:29:55.000000000 +0000 @@ -9,15 +9,12 @@ # to work without modifications. # NOTE: This script assumes you are running it from a directory which contains -# arcanist/, libphutil/, and phabricator/. +# arcanist/ and phabricator/. ROOT=`pwd` # You can hard-code the path here instead. ### UPDATE WORKING COPIES ###################################################### -cd $ROOT/libphutil -git pull - cd $ROOT/arcanist git pull diff -Nru phabricator-0~git20200925/phabricator/scripts/repository/commit_hook.php phabricator-0~git20220903/phabricator/scripts/repository/commit_hook.php --- phabricator-0~git20200925/phabricator/scripts/repository/commit_hook.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/repository/commit_hook.php 2022-06-14 16:29:55.000000000 +0000 @@ -122,9 +122,9 @@ if (!strlen($username)) { throw new Exception( pht( - 'No Direct Pushes: You are pushing directly to a repository hosted '. - 'by Phabricator. This will not work. See "No Direct Pushes" in the '. - 'documentation for more information.')); + 'No Direct Pushes: You are pushing directly to a hosted repository. '. + 'This will not work. See "No Direct Pushes" in the documentation '. + 'for more information.')); } if ($repository->isHg()) { diff -Nru phabricator-0~git20200925/phabricator/scripts/setup/manage_celerity.php phabricator-0~git20220903/phabricator/scripts/setup/manage_celerity.php --- phabricator-0~git20200925/phabricator/scripts/setup/manage_celerity.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/setup/manage_celerity.php 2022-06-14 16:29:55.000000000 +0000 @@ -2,7 +2,7 @@ <?php $root = dirname(dirname(dirname(__FILE__))); -require_once $root.'/scripts/__init_script__.php'; +require_once $root.'/scripts/init/init-setup.php'; $args = new PhutilArgumentParser($argv); $args->setTagline(pht('manage celerity')); diff -Nru phabricator-0~git20200925/phabricator/scripts/sql/manage_storage.php phabricator-0~git20220903/phabricator/scripts/sql/manage_storage.php --- phabricator-0~git20200925/phabricator/scripts/sql/manage_storage.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/sql/manage_storage.php 2022-06-14 16:29:55.000000000 +0000 @@ -5,13 +5,13 @@ require_once $root.'/scripts/init/init-setup.php'; $args = new PhutilArgumentParser($argv); -$args->setTagline(pht('manage Phabricator storage and schemata')); +$args->setTagline(pht('manage storage and schemata')); $args->setSynopsis(<<<EOHELP **storage** __workflow__ [__options__] -Manage Phabricator database storage and schema versioning. +Manage database storage and schema versioning. **storage** upgrade -Initialize or upgrade Phabricator storage. +Initialize or upgrade storage. **storage** upgrade --user __root__ --password __hunter2__ Use administrative credentials for schema changes. @@ -74,7 +74,7 @@ 'name' => 'disable-utf8mb4', 'help' => pht( 'Disable %s, even if the database supports it. This is an '. - 'advanced feature used for testing changes to Phabricator; you '. + 'advanced feature used for testing internal changes; you '. 'should not normally use this flag.', 'utf8mb4'), ), @@ -95,7 +95,7 @@ $host = $args->getArg('host'); $ref_key = $args->getArg('ref'); -if (strlen($host) || strlen($ref_key)) { +if (($host !== null) || ($ref_key !== null)) { if ($host && $ref_key) { throw new PhutilArgumentUsageException( pht( @@ -168,9 +168,9 @@ 'Unable to connect to MySQL using the configured credentials. '. 'You must configure standard credentials before you can upgrade '. 'storage. Run these commands to set up credentials:'), - " phabricator/ $ ./bin/config set mysql.host __host__\n". - " phabricator/ $ ./bin/config set mysql.user __username__\n". - " phabricator/ $ ./bin/config set mysql.pass __password__", + " $ ./bin/config set mysql.host __host__\n". + " $ ./bin/config set mysql.user __username__\n". + " $ ./bin/config set mysql.pass __password__", pht( 'These standard credentials are separate from any administrative '. 'credentials provided to this command with __%s__ or '. diff -Nru phabricator-0~git20200925/phabricator/scripts/ssh/ssh-auth.php phabricator-0~git20220903/phabricator/scripts/ssh/ssh-auth.php --- phabricator-0~git20200925/phabricator/scripts/ssh/ssh-auth.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/ssh/ssh-auth.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,6 +4,11 @@ $root = dirname(dirname(dirname(__FILE__))); require_once $root.'/scripts/init/init-script.php'; +$error_log = id(new PhutilErrorLog()) + ->setLogName(pht('SSH Error Log')) + ->setLogPath(PhabricatorEnv::getEnvConfig('log.ssh-error.path')) + ->activateLog(); + // TODO: For now, this is using "parseParital()", not "parse()". This allows // the script to accept (and ignore) additional arguments. This preserves // backward compatibility until installs have time to migrate to the new diff -Nru phabricator-0~git20200925/phabricator/scripts/ssh/ssh-connect.php phabricator-0~git20220903/phabricator/scripts/ssh/ssh-connect.php --- phabricator-0~git20200925/phabricator/scripts/ssh/ssh-connect.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/ssh/ssh-connect.php 2022-06-14 16:29:55.000000000 +0000 @@ -154,6 +154,6 @@ array_unshift($arguments, $pattern); $err = newv('PhutilExecPassthru', $arguments) - ->execute(); + ->resolve(); exit($err); diff -Nru phabricator-0~git20200925/phabricator/scripts/ssh/ssh-exec.php phabricator-0~git20220903/phabricator/scripts/ssh/ssh-exec.php --- phabricator-0~git20200925/phabricator/scripts/ssh/ssh-exec.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/scripts/ssh/ssh-exec.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,7 +4,12 @@ $ssh_start_time = microtime(true); $root = dirname(dirname(dirname(__FILE__))); -require_once $root.'/scripts/__init_script__.php'; +require_once $root.'/scripts/init/init-script.php'; + +$error_log = id(new PhutilErrorLog()) + ->setLogName(pht('SSH Error Log')) + ->setLogPath(PhabricatorEnv::getEnvConfig('log.ssh-error.path')) + ->activateLog(); $ssh_log = PhabricatorSSHLog::getLog(); @@ -125,9 +130,9 @@ if (!PhabricatorEnv::isClusterAddress($remote_address)) { throw new Exception( pht( - 'This request originates from outside of the Phabricator cluster '. - 'address range. Requests signed with a trusted device key must '. - 'originate from trusted hosts.')); + 'This request originates from outside of the cluster address range. '. + 'Requests signed with a trusted device key must originate from '. + 'trusted hosts.')); } $device = id(new AlmanacDeviceQuery()) @@ -141,6 +146,14 @@ $device_name)); } + if ($device->isDisabled()) { + throw new Exception( + pht( + 'This request has authenticated as a device ("%s"), but this '. + 'device is disabled.', + $device->getName())); + } + // We're authenticated as a device, but we're going to read the user out of // the command below. $is_cluster_request = true; @@ -215,7 +228,9 @@ $command_list = implode(', ', $command_list); $error_lines = array(); - $error_lines[] = pht('Welcome to Phabricator.'); + $error_lines[] = pht( + 'Welcome to %s.', + PlatformSymbols::getPlatformServerName()); $error_lines[] = pht( 'You are logged in as %s.', $user_name); @@ -223,7 +238,7 @@ if (!$original_argv) { $error_lines[] = pht( 'You have not specified a command to run. This means you are requesting '. - 'an interactive shell, but Phabricator does not provide interactive '. + 'an interactive shell, but this server does not provide interactive '. 'shells over SSH.'); $error_lines[] = pht( '(Usually, you should run a command like "git clone" or "hg push" '. @@ -257,7 +272,7 @@ if (empty($workflows[$command])) { $error_lines[] = pht( 'You have specified the command "%s", but that command is not '. - 'supported by Phabricator. As received by Phabricator, your entire '. + 'supported by this server. As received by this server, your entire '. 'argument list was:', $command); diff -Nru phabricator-0~git20200925/phabricator/src/aphront/AphrontRequest.php phabricator-0~git20220903/phabricator/src/aphront/AphrontRequest.php --- phabricator-0~git20200925/phabricator/src/aphront/AphrontRequest.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/aphront/AphrontRequest.php 2022-06-14 16:29:55.000000000 +0000 @@ -227,6 +227,43 @@ /** * @task data */ + public function getJSONMap($name, $default = array()) { + if (!isset($this->requestData[$name])) { + return $default; + } + + $raw_data = phutil_string_cast($this->requestData[$name]); + $raw_data = trim($raw_data); + if (!strlen($raw_data)) { + return $default; + } + + if ($raw_data[0] !== '{') { + throw new Exception( + pht( + 'Request parameter "%s" is not formatted properly. Expected a '. + 'JSON object, but value does not start with "{".', + $name)); + } + + try { + $json_object = phutil_json_decode($raw_data); + } catch (PhutilJSONParserException $ex) { + throw new Exception( + pht( + 'Request parameter "%s" is not formatted properly. Expected a '. + 'JSON object, but encountered a syntax error: %s.', + $name, + $ex->getMessage())); + } + + return $json_object; + } + + + /** + * @task data + */ public function getArr($name, $default = array()) { if (isset($this->requestData[$name]) && is_array($this->requestData[$name])) { @@ -317,9 +354,9 @@ $info = array(); $info[] = pht( - 'You are trying to save some data to Phabricator, but the request '. - 'your browser made included an incorrect token. Reload the page '. - 'and try again. You may need to clear your cookies.'); + 'You are trying to save some data to permanent storage, but the '. + 'request your browser made included an incorrect token. Reload the '. + 'page and try again. You may need to clear your cookies.'); if ($this->isAjax()) { $info[] = pht('This was an Ajax request.'); @@ -550,11 +587,11 @@ throw new AphrontMalformedRequestException( pht('Bad Host Header'), pht( - 'This Phabricator install is configured as "%s", but you are '. - 'using the domain name "%s" to access a page which is trying to '. - 'set a cookie. Access Phabricator on the configured primary '. - 'domain or a configured alternate domain. Phabricator will not '. - 'set cookies on other domains for security reasons.', + 'This server is configured as "%s", but you are using the domain '. + 'name "%s" to access a page which is trying to set a cookie. '. + 'Access this service on the configured primary domain or a '. + 'configured alternate domain. Cookies will not be set on other '. + 'domains for security reasons.', $configured_as, $accessed_as), true); diff -Nru phabricator-0~git20200925/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php phabricator-0~git20220903/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php --- phabricator-0~git20200925/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/aphront/configuration/AphrontApplicationConfiguration.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return $request; } - public function build404Controller() { - return array(new Phabricator404Controller(), array()); - } - public function buildRedirectController($uri, $external) { return array( new PhabricatorRedirectController(), @@ -87,7 +83,7 @@ * @phutil-external-symbol class PhabricatorStartup */ public static function runHTTPRequest(AphrontHTTPSink $sink) { - if (isset($_SERVER['HTTP_X_PHABRICATOR_SELFCHECK'])) { + if (isset($_SERVER['HTTP_X_SETUP_SELFCHECK'])) { $response = self::newSelfCheckResponse(); return self::writeResponse($sink, $response); } @@ -176,7 +172,7 @@ } $host = AphrontRequest::getHTTPHeader('Host'); - $path = $_REQUEST['__path__']; + $path = PhabricatorStartup::getRequestPath(); $application = new self(); @@ -423,9 +419,9 @@ throw new AphrontMalformedRequestException( pht('No %s', 'SERVER_ADDR'), pht( - 'Phabricator is configured to operate in cluster mode, but '. + 'This service is configured to operate in cluster mode, but '. '%s is not defined in the request context. Your webserver '. - 'configuration needs to forward %s to PHP so Phabricator can '. + 'configuration needs to forward %s to PHP so the software can '. 'reject requests received on external interfaces.', 'SERVER_ADDR', 'SERVER_ADDR')); @@ -435,7 +431,7 @@ throw new AphrontMalformedRequestException( pht('External Interface'), pht( - 'Phabricator is configured in cluster mode and the address '. + 'This service is configured in cluster mode and the address '. 'this request was received on ("%s") is not whitelisted as '. 'a cluster address.', $server_addr)); @@ -504,7 +500,10 @@ return array($result, array()); } - return $this->build404Controller(); + throw new Exception( + pht( + 'Aphront site ("%s") failed to build a 404 controller.', + get_class($site))); } /** @@ -759,7 +758,7 @@ } private static function newSelfCheckResponse() { - $path = idx($_REQUEST, '__path__', ''); + $path = PhabricatorStartup::getRequestPath(); $query = idx($_SERVER, 'QUERY_STRING', ''); $pairs = id(new PhutilQueryStringParser()) diff -Nru phabricator-0~git20200925/phabricator/src/aphront/httpparametertype/AphrontJSONHTTPParameterType.php phabricator-0~git20220903/phabricator/src/aphront/httpparametertype/AphrontJSONHTTPParameterType.php --- phabricator-0~git20200925/phabricator/src/aphront/httpparametertype/AphrontJSONHTTPParameterType.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/aphront/httpparametertype/AphrontJSONHTTPParameterType.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,31 @@ +<?php + +final class AphrontJSONHTTPParameterType + extends AphrontHTTPParameterType { + + protected function getParameterDefault() { + return array(); + } + + protected function getParameterValue(AphrontRequest $request, $key) { + $str = $request->getStr($key); + return phutil_json_decode($str); + } + + protected function getParameterTypeName() { + return 'string (json object)'; + } + + protected function getParameterFormatDescriptions() { + return array( + pht('A JSON-encoded object.'), + ); + } + + protected function getParameterExamples() { + return array( + 'v={...}', + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/aphront/httpparametertype/AphrontRemarkupHTTPParameterType.php phabricator-0~git20220903/phabricator/src/aphront/httpparametertype/AphrontRemarkupHTTPParameterType.php --- phabricator-0~git20200925/phabricator/src/aphront/httpparametertype/AphrontRemarkupHTTPParameterType.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/aphront/httpparametertype/AphrontRemarkupHTTPParameterType.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,50 @@ +<?php + +final class AphrontRemarkupHTTPParameterType + extends AphrontHTTPParameterType { + + protected function getParameterDefault() { + return $this->newRemarkupValue(); + } + + protected function getParameterValue(AphrontRequest $request, $key) { + $corpus_key = $key; + $corpus_type = new AphrontStringHTTPParameterType(); + $corpus_value = $this->getValueWithType( + $corpus_type, + $request, + $corpus_key); + + $metadata_key = $key.'_metadata'; + $metadata_type = new AphrontJSONHTTPParameterType(); + $metadata_value = $this->getValueWithType( + $metadata_type, + $request, + $metadata_key); + + return $this->newRemarkupValue() + ->setCorpus($corpus_value) + ->setMetadata($metadata_value); + } + + protected function getParameterTypeName() { + return 'string (remarkup)'; + } + + protected function getParameterFormatDescriptions() { + return array( + pht('Remarkup text.'), + ); + } + + protected function getParameterExamples() { + return array( + 'v=Lorem...', + ); + } + + private function newRemarkupValue() { + return new RemarkupValue(); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/aphront/response/Aphront404Response.php phabricator-0~git20220903/phabricator/src/aphront/response/Aphront404Response.php --- phabricator-0~git20200925/phabricator/src/aphront/response/Aphront404Response.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/aphront/response/Aphront404Response.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,10 +10,17 @@ $request = $this->getRequest(); $viewer = $request->getViewer(); + // See T13636. Note that this response may be served from a Site other than + // the primary PlatformSite. For now, always link to the PlatformSite. + + // (This may not be the best possible place to send users who are currently + // on "real" sites, like the BlogSite.) + $return_uri = PhabricatorEnv::getURI('/'); + $dialog = id(new AphrontDialogView()) ->setViewer($viewer) ->setTitle(pht('404 Not Found')) - ->addCancelButton('/', pht('Return to Charted Waters')) + ->addCancelButton($return_uri, pht('Return to Charted Waters')) ->appendParagraph( pht( 'You arrive at your destination, but there is nothing here.')) diff -Nru phabricator-0~git20200925/phabricator/src/aphront/site/AphrontSite.php phabricator-0~git20220903/phabricator/src/aphront/site/AphrontSite.php --- phabricator-0~git20200925/phabricator/src/aphront/site/AphrontSite.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/aphront/site/AphrontSite.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,7 +10,7 @@ abstract public function getRoutingMaps(); public function new404Controller(AphrontRequest $request) { - return null; + return new Phabricator404Controller(); } protected function isHostMatch($host, array $uris) { diff -Nru phabricator-0~git20200925/phabricator/src/aphront/site/PhabricatorPlatformSite.php phabricator-0~git20220903/phabricator/src/aphront/site/PhabricatorPlatformSite.php --- phabricator-0~git20200925/phabricator/src/aphront/site/PhabricatorPlatformSite.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/aphront/site/PhabricatorPlatformSite.php 2022-06-14 16:29:55.000000000 +0000 @@ -50,4 +50,8 @@ return $maps; } + public function new404Controller(AphrontRequest $request) { + return new PhabricatorPlatform404Controller(); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/constants/AlmanacDeviceStatus.php phabricator-0~git20220903/phabricator/src/applications/almanac/constants/AlmanacDeviceStatus.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/constants/AlmanacDeviceStatus.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/constants/AlmanacDeviceStatus.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,110 @@ +<?php + +final class AlmanacDeviceStatus + extends Phobject { + + const ACTIVE = 'active'; + const DISABLED = 'disabled'; + + private $value; + + public static function newStatusFromValue($value) { + $status = new self(); + $status->value = $value; + return $status; + } + + public function getValue() { + return $this->value; + } + + public function getName() { + $name = $this->getDeviceStatusProperty('name'); + + if ($name === null) { + $name = pht('Unknown Almanac Device Status ("%s")', $this->getValue()); + } + + return $name; + } + + public function getIconIcon() { + return $this->getDeviceStatusProperty('icon.icon'); + } + + public function getIconColor() { + return $this->getDeviceStatusProperty('icon.color'); + } + + public function isDisabled() { + return ($this->getValue() === self::DISABLED); + } + + public function hasStatusTag() { + return ($this->getStatusTagIcon() !== null); + } + + public function getStatusTagIcon() { + return $this->getDeviceStatusProperty('status-tag.icon'); + } + + public function getStatusTagColor() { + return $this->getDeviceStatusProperty('status-tag.color'); + } + + public static function getStatusMap() { + $result = array(); + + foreach (self::newDeviceStatusMap() as $status_value => $ignored) { + $result[$status_value] = self::newStatusFromValue($status_value); + } + + return $result; + } + + public static function getActiveStatusList() { + $results = array(); + foreach (self::newDeviceStatusMap() as $status_value => $status) { + if (empty($status['disabled'])) { + $results[] = $status_value; + } + } + return $results; + } + + public static function getDisabledStatusList() { + $results = array(); + foreach (self::newDeviceStatusMap() as $status_value => $status) { + if (!empty($status['disabled'])) { + $results[] = $status_value; + } + } + return $results; + } + + private function getDeviceStatusProperty($key, $default = null) { + $map = self::newDeviceStatusMap(); + $properties = idx($map, $this->getValue(), array()); + return idx($properties, $key, $default); + } + + private static function newDeviceStatusMap() { + return array( + self::ACTIVE => array( + 'name' => pht('Active'), + 'icon.icon' => 'fa-server', + 'icon.color' => 'green', + ), + self::DISABLED => array( + 'name' => pht('Disabled'), + 'icon.icon' => 'fa-times', + 'icon.color' => 'grey', + 'status-tag.icon' => 'fa-times', + 'status-tag.color' => 'indigo', + 'disabled' => true, + ), + ); + } + + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/controller/AlmanacDeviceViewController.php phabricator-0~git20220903/phabricator/src/applications/almanac/controller/AlmanacDeviceViewController.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/controller/AlmanacDeviceViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/controller/AlmanacDeviceViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -31,6 +31,14 @@ ->setPolicyObject($device) ->setHeaderIcon('fa-server'); + $status = $device->getStatusObject(); + if ($status->hasStatusTag()) { + $header->setStatus( + $status->getStatusTagIcon(), + $status->getStatusTagColor(), + $status->getName()); + } + $issue = null; if ($device->isClusterDevice()) { $issue = $this->addClusterMessage( diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/editor/AlmanacDeviceEditEngine.php phabricator-0~git20220903/phabricator/src/applications/almanac/editor/AlmanacDeviceEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/editor/AlmanacDeviceEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/editor/AlmanacDeviceEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -76,6 +76,8 @@ } protected function buildCustomEditFields($object) { + $status_map = $this->getDeviceStatusMap($object); + return array( id(new PhabricatorTextEditField()) ->setKey('name') @@ -84,7 +86,32 @@ ->setTransactionType(AlmanacDeviceNameTransaction::TRANSACTIONTYPE) ->setIsRequired(true) ->setValue($object->getName()), + id(new PhabricatorSelectEditField()) + ->setKey('status') + ->setLabel(pht('Status')) + ->setDescription(pht('Device status.')) + ->setTransactionType(AlmanacDeviceStatusTransaction::TRANSACTIONTYPE) + ->setOptions($status_map) + ->setValue($object->getStatus()), ); } + + private function getDeviceStatusMap(AlmanacDevice $device) { + $status_map = AlmanacDeviceStatus::getStatusMap(); + + // If the device currently has an unknown status, add it to the list for + // the dropdown. + $status_value = $device->getStatus(); + if (!isset($status_map[$status_value])) { + $status_map = array( + $status_value => AlmanacDeviceStatus::newStatusFromValue($status_value), + ) + $status_map; + } + + $status_map = mpull($status_map, 'getName'); + + return $status_map; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/engineextension/AlmanacBindingsSearchEngineAttachment.php phabricator-0~git20220903/phabricator/src/applications/almanac/engineextension/AlmanacBindingsSearchEngineAttachment.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/engineextension/AlmanacBindingsSearchEngineAttachment.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/engineextension/AlmanacBindingsSearchEngineAttachment.php 2022-06-14 16:29:55.000000000 +0000 @@ -3,6 +3,17 @@ final class AlmanacBindingsSearchEngineAttachment extends AlmanacSearchEngineAttachment { + private $isActive; + + public function setIsActive($is_active) { + $this->isActive = $is_active; + return $this; + } + + public function getIsActive() { + return $this->isActive; + } + public function getAttachmentName() { return pht('Almanac Bindings'); } @@ -13,12 +24,24 @@ public function willLoadAttachmentData($query, $spec) { $query->needProperties(true); - $query->needBindings(true); + + if ($this->getIsActive()) { + $query->needActiveBindings(true); + } else { + $query->needBindings(true); + } } public function getAttachmentForObject($object, $data, $spec) { $bindings = array(); - foreach ($object->getBindings() as $binding) { + + if ($this->getIsActive()) { + $service_bindings = $object->getActiveBindings(); + } else { + $service_bindings = $object->getBindings(); + } + + foreach ($service_bindings as $binding) { $bindings[] = $this->getAlmanacBindingDictionary($binding); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php phabricator-0~git20220903/phabricator/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php 2022-06-14 16:29:55.000000000 +0000 @@ -51,6 +51,8 @@ 'phid' => $device->getPHID(), 'name' => $device->getName(), 'properties' => $this->getAlmanacPropertyList($device), + 'status' => $device->getStatus(), + 'disabled' => $device->isDisabled(), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php phabricator-0~git20220903/phabricator/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -147,10 +147,9 @@ if (!$public_key) { throw new PhutilArgumentUsageException( pht( - 'The public key corresponding to the given private key is not '. - 'yet known to Phabricator. Associate the public key with an '. - 'Almanac device in the web interface before registering hosts '. - 'with it.')); + 'The public key corresponding to the given private key is unknown. '. + 'Associate the public key with an Almanac device in the web '. + 'interface before registering hosts with it.')); } if ($public_key->getObjectPHID() !== $device->getPHID()) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php phabricator-0~git20220903/phabricator/src/applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -61,14 +61,14 @@ phutil_console_wrap( pht( 'Trusting a public key gives anyone holding the corresponding '. - 'private key complete, unrestricted access to all data in '. - 'Phabricator. The private key will be able to sign requests that '. - 'skip policy and security checks.')), + 'private key complete, unrestricted access to all data. The '. + 'private key will be able to sign requests that bypass policy and '. + 'security checks.')), phutil_console_wrap( pht( 'This is an advanced feature which should normally be used only '. - 'when building a Phabricator cluster. This feature is very '. - 'dangerous if misused.')), + 'when building a cluster. This feature is very dangerous if '. + 'misused.')), pht('This key is associated with device "%s".', $handle->getName())); $prompt = pht( diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/phid/AlmanacInterfacePHIDType.php phabricator-0~git20220903/phabricator/src/applications/almanac/phid/AlmanacInterfacePHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/phid/AlmanacInterfacePHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/phid/AlmanacInterfacePHIDType.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,7 +34,8 @@ $id = $interface->getID(); - $device_name = $interface->getDevice()->getName(); + $device = $interface->getDevice(); + $device_name = $device->getName(); $address = $interface->getAddress(); $port = $interface->getPort(); $network = $interface->getNetwork()->getName(); @@ -48,6 +49,10 @@ $handle->setObjectName(pht('Interface %d', $id)); $handle->setName($name); + + if ($device->isDisabled()) { + $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED); + } } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacBindingQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacBindingQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacBindingQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacBindingQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,6 +8,7 @@ private $servicePHIDs; private $devicePHIDs; private $interfacePHIDs; + private $isActive; public function withIDs(array $ids) { $this->ids = $ids; @@ -34,12 +35,13 @@ return $this; } - public function newResultObject() { - return new AlmanacBinding(); + public function withIsActive($active) { + $this->isActive = $active; + return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); + public function newResultObject() { + return new AlmanacBinding(); } protected function willFilterPage(array $bindings) { @@ -95,39 +97,79 @@ if ($this->ids !== null) { $where[] = qsprintf( $conn, - 'id IN (%Ld)', + 'binding.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, - 'phid IN (%Ls)', + 'binding.phid IN (%Ls)', $this->phids); } if ($this->servicePHIDs !== null) { $where[] = qsprintf( $conn, - 'servicePHID IN (%Ls)', + 'binding.servicePHID IN (%Ls)', $this->servicePHIDs); } if ($this->devicePHIDs !== null) { $where[] = qsprintf( $conn, - 'devicePHID IN (%Ls)', + 'binding.devicePHID IN (%Ls)', $this->devicePHIDs); } if ($this->interfacePHIDs !== null) { $where[] = qsprintf( $conn, - 'interfacePHID IN (%Ls)', + 'binding.interfacePHID IN (%Ls)', $this->interfacePHIDs); } + if ($this->isActive !== null) { + if ($this->isActive) { + $where[] = qsprintf( + $conn, + '(binding.isDisabled = 0) AND (device.status IN (%Ls))', + AlmanacDeviceStatus::getActiveStatusList()); + } else { + $where[] = qsprintf( + $conn, + '(binding.isDisabled = 1) OR (device.status IN (%Ls))', + AlmanacDeviceStatus::getDisabledStatusList()); + } + } + return $where; } + protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { + $joins = parent::buildJoinClauseParts($conn); + + if ($this->shouldJoinDeviceTable()) { + $device_table = new AlmanacDevice(); + $joins[] = qsprintf( + $conn, + 'JOIN %R device ON binding.devicePHID = device.phid', + $device_table); + } + + return $joins; + } + + private function shouldJoinDeviceTable() { + if ($this->isActive !== null) { + return true; + } + + return false; + } + + protected function getPrimaryTableAlias() { + return 'binding'; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacDeviceQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacDeviceQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacDeviceQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacDeviceQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,6 +9,7 @@ private $namePrefix; private $nameSuffix; private $isClusterDevice; + private $statuses; public function withIDs(array $ids) { $this->ids = $ids; @@ -35,6 +36,11 @@ return $this; } + public function withStatuses(array $statuses) { + $this->statuses = $statuses; + return $this; + } + public function withNameNgrams($ngrams) { return $this->withNgramsConstraint( new AlmanacDeviceNameNgrams(), @@ -50,10 +56,6 @@ return new AlmanacDevice(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); @@ -103,6 +105,13 @@ (int)$this->isClusterDevice); } + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn, + 'device.status IN (%Ls)', + $this->statuses); + } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacDeviceSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacDeviceSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacDeviceSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacDeviceSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -16,6 +16,9 @@ } protected function buildCustomSearchFields() { + $status_options = AlmanacDeviceStatus::getStatusMap(); + $status_options = mpull($status_options, 'getName'); + return array( id(new PhabricatorSearchTextField()) ->setLabel(pht('Name Contains')) @@ -25,6 +28,11 @@ ->setLabel(pht('Exact Names')) ->setKey('names') ->setDescription(pht('Search for devices with specific names.')), + id(new PhabricatorSearchCheckboxesField()) + ->setLabel(pht('Statuses')) + ->setKey('statuses') + ->setDescription(pht('Search for devices with given statuses.')) + ->setOptions($status_options), id(new PhabricatorSearchThreeStateField()) ->setLabel(pht('Cluster Device')) ->setKey('isClusterDevice') @@ -50,6 +58,10 @@ $query->withIsClusterDevice($map['isClusterDevice']); } + if ($map['statuses']) { + $query->withStatuses($map['statuses']); + } + return $query; } @@ -59,6 +71,7 @@ protected function getBuiltinQueryNames() { $names = array( + 'active' => pht('Active Devices'), 'all' => pht('All Devices'), ); @@ -66,11 +79,13 @@ } public function buildSavedQueryFromBuiltin($query_key) { - $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { + case 'active': + $active_statuses = AlmanacDeviceStatus::getActiveStatusList(); + return $query->setParameter('statuses', $active_statuses); case 'all': return $query; } @@ -99,6 +114,19 @@ $item->addIcon('fa-sitemap', pht('Cluster Device')); } + if ($device->isDisabled()) { + $item->setDisabled(true); + } + + $status = $device->getStatusObject(); + $icon_icon = $status->getIconIcon(); + $icon_color = $status->getIconColor(); + $icon_label = $status->getName(); + + $item->setStatusIcon( + "{$icon_icon} {$icon_color}", + $icon_label); + $list->addItem($item); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacInterfaceQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacInterfaceQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacInterfaceQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacInterfaceQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new AlmanacInterface(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $interfaces) { $network_phids = mpull($interfaces, 'getNetworkPHID'); $device_phids = mpull($interfaces, 'getDevicePHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacInterfaceTransactionQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacInterfaceTransactionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacInterfaceTransactionQuery.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacInterfaceTransactionQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,10 @@ +<?php + +final class AlmanacInterfaceTransactionQuery + extends PhabricatorApplicationTransactionQuery { + + public function getTemplateApplicationTransaction() { + return new AlmanacInterfaceTransaction(); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacNamespaceQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacNamespaceQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacNamespaceQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacNamespaceQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new AlmanacNamespace(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacNetworkQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacNetworkQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacNetworkQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacNetworkQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ $ngrams); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacPropertyQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacPropertyQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacPropertyQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacPropertyQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -33,10 +33,6 @@ return new AlmanacProperty(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $properties) { $object_phids = mpull($properties, 'getObjectPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacServiceQuery.php phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacServiceQuery.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/query/AlmanacServiceQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/query/AlmanacServiceQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -12,6 +12,7 @@ private $nameSuffix; private $needBindings; + private $needActiveBindings; public function withIDs(array $ids) { $this->ids = $ids; @@ -59,12 +60,13 @@ return $this; } - public function newResultObject() { - return new AlmanacService(); + public function needActiveBindings($need_active) { + $this->needActiveBindings = $need_active; + return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); + public function newResultObject() { + return new AlmanacService(); } protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { @@ -160,18 +162,35 @@ } protected function didFilterPage(array $services) { - if ($this->needBindings) { + $need_all = $this->needBindings; + $need_active = $this->needActiveBindings; + + $need_any = ($need_all || $need_active); + $only_active = ($need_active && !$need_all); + + if ($need_any) { $service_phids = mpull($services, 'getPHID'); - $bindings = id(new AlmanacBindingQuery()) + + $bindings_query = id(new AlmanacBindingQuery()) ->setViewer($this->getViewer()) ->withServicePHIDs($service_phids) - ->needProperties($this->getNeedProperties()) - ->execute(); + ->needProperties($this->getNeedProperties()); + + if ($only_active) { + $bindings_query->withIsActive(true); + } + + $bindings = $bindings_query->execute(); $bindings = mgroup($bindings, 'getServicePHID'); foreach ($services as $service) { $service_bindings = idx($bindings, $service->getPHID(), array()); - $service->attachBindings($service_bindings); + + if ($only_active) { + $service->attachActiveBindings($service_bindings); + } else { + $service->attachBindings($service_bindings); + } } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php phabricator-0~git20220903/phabricator/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/servicetype/AlmanacClusterDatabaseServiceType.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,12 +10,12 @@ } public function getServiceTypeName() { - return pht('Phabricator Cluster: Database'); + return pht('Cluster: Database'); } public function getServiceTypeDescription() { return pht( - 'Defines a database service for use in a Phabricator cluster.'); + 'Defines a database service for use in a cluster.'); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php phabricator-0~git20220903/phabricator/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/servicetype/AlmanacClusterRepositoryServiceType.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,12 +10,12 @@ } public function getServiceTypeName() { - return pht('Phabricator Cluster: Repository'); + return pht('Cluster: Repository'); } public function getServiceTypeDescription() { return pht( - 'Defines a repository service for use in a Phabricator cluster.'); + 'Defines a repository service for use in a cluster.'); } public function getFieldSpecifications() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacBinding.php phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacBinding.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacBinding.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacBinding.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,7 +13,6 @@ protected $servicePHID; protected $devicePHID; protected $interfacePHID; - protected $mailKey; protected $isDisabled; private $service = self::ATTACHABLE; @@ -33,7 +32,6 @@ return array( self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( - 'mailKey' => 'bytes20', 'isDisabled' => 'bool', ), self::CONFIG_KEY_SCHEMA => array( @@ -51,15 +49,8 @@ ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID(AlmanacBindingPHIDType::TYPECONST); - } - - public function save() { - if (!$this->mailKey) { - $this->mailKey = Filesystem::readRandomCharacters(20); - } - return parent::save(); + public function getPHIDType() { + return AlmanacBindingPHIDType::TYPECONST; } public function getName() { @@ -67,7 +58,9 @@ } public function getURI() { - return '/almanac/binding/'.$this->getID().'/'; + return urisprintf( + '/almanac/binding/%s/', + $this->getID()); } public function getService() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacDevice.php phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacDevice.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacDevice.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacDevice.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,9 +15,9 @@ protected $name; protected $nameIndex; - protected $mailKey; protected $viewPolicy; protected $editPolicy; + protected $status; protected $isBoundToClusterService; private $almanacProperties = self::ATTACHABLE; @@ -26,6 +26,7 @@ return id(new AlmanacDevice()) ->setViewPolicy(PhabricatorPolicies::POLICY_USER) ->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN) + ->setStatus(AlmanacDeviceStatus::ACTIVE) ->attachAlmanacProperties(array()) ->setIsBoundToClusterService(0); } @@ -36,7 +37,7 @@ self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'text128', 'nameIndex' => 'bytes12', - 'mailKey' => 'bytes20', + 'status' => 'text32', 'isBoundToClusterService' => 'bool', ), self::CONFIG_KEY_SCHEMA => array( @@ -51,8 +52,8 @@ ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID(AlmanacDevicePHIDType::TYPECONST); + public function getPHIDType() { + return AlmanacDevicePHIDType::TYPECONST; } public function save() { @@ -60,15 +61,13 @@ $this->nameIndex = PhabricatorHash::digestForIndex($this->getName()); - if (!$this->mailKey) { - $this->mailKey = Filesystem::readRandomCharacters(20); - } - return parent::save(); } public function getURI() { - return '/almanac/device/view/'.$this->getName().'/'; + return urisprintf( + '/almanac/device/view/%s/', + $this->getName()); } public function rebuildClusterBindingStatus() { @@ -90,8 +89,8 @@ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); queryfx( $this->establishConnection('w'), - 'UPDATE %T SET isBoundToClusterService = %d WHERE id = %d', - $this->getTableName(), + 'UPDATE %R SET isBoundToClusterService = %d WHERE id = %d', + $this, $this->getIsBoundToClusterService(), $this->getID()); unset($unguarded); @@ -104,6 +103,18 @@ return $this->getIsBoundToClusterService(); } + public function getStatusObject() { + return $this->newStatusObject(); + } + + private function newStatusObject() { + return AlmanacDeviceStatus::newStatusFromValue($this->getStatus()); + } + + public function isDisabled() { + return $this->getStatusObject()->isDisabled(); + } + /* -( AlmanacPropertyInterface )------------------------------------------- */ @@ -267,12 +278,27 @@ ->setKey('name') ->setType('string') ->setDescription(pht('The name of the device.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('status') + ->setType('map<string, wild>') + ->setDescription(pht('Device status information.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('disabled') + ->setType('bool') + ->setDescription(pht('True if device is disabled.')), ); } public function getFieldValuesForConduit() { + $status = $this->getStatusObject(); + return array( 'name' => $this->getName(), + 'status' => array( + 'value' => $status->getValue(), + 'name' => $status->getName(), + ), + 'disabled' => $this->isDisabled(), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacNamespace.php phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacNamespace.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacNamespace.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacNamespace.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,24 +6,19 @@ PhabricatorPolicyInterface, PhabricatorApplicationTransactionInterface, PhabricatorProjectInterface, - AlmanacPropertyInterface, PhabricatorDestructibleInterface, PhabricatorNgramsInterface, PhabricatorConduitResultInterface { protected $name; protected $nameIndex; - protected $mailKey; protected $viewPolicy; protected $editPolicy; - private $almanacProperties = self::ATTACHABLE; - public static function initializeNewNamespace() { return id(new self()) ->setViewPolicy(PhabricatorPolicies::POLICY_USER) - ->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN) - ->attachAlmanacProperties(array()); + ->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN); } protected function getConfiguration() { @@ -32,7 +27,6 @@ self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'text128', 'nameIndex' => 'bytes12', - 'mailKey' => 'bytes20', ), self::CONFIG_KEY_SCHEMA => array( 'key_nameindex' => array( @@ -46,9 +40,8 @@ ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - AlmanacNamespacePHIDType::TYPECONST); + public function getPHIDType() { + return AlmanacNamespacePHIDType::TYPECONST; } public function save() { @@ -56,15 +49,13 @@ $this->nameIndex = PhabricatorHash::digestForIndex($this->getName()); - if (!$this->mailKey) { - $this->mailKey = Filesystem::readRandomCharacters(20); - } - return parent::save(); } public function getURI() { - return '/almanac/namespace/view/'.$this->getName().'/'; + return urisprintf( + '/almanac/namespace/view/%s/', + $this->getName()); } public function getNameLength() { @@ -113,53 +104,6 @@ } -/* -( AlmanacPropertyInterface )------------------------------------------- */ - - - public function attachAlmanacProperties(array $properties) { - assert_instances_of($properties, 'AlmanacProperty'); - $this->almanacProperties = mpull($properties, null, 'getFieldName'); - return $this; - } - - public function getAlmanacProperties() { - return $this->assertAttached($this->almanacProperties); - } - - public function hasAlmanacProperty($key) { - $this->assertAttached($this->almanacProperties); - return isset($this->almanacProperties[$key]); - } - - public function getAlmanacProperty($key) { - return $this->assertAttachedKey($this->almanacProperties, $key); - } - - public function getAlmanacPropertyValue($key, $default = null) { - if ($this->hasAlmanacProperty($key)) { - return $this->getAlmanacProperty($key)->getFieldValue(); - } else { - return $default; - } - } - - public function getAlmanacPropertyFieldSpecifications() { - return array(); - } - - public function newAlmanacPropertyEditEngine() { - throw new PhutilMethodNotImplementedException(); - } - - public function getAlmanacPropertySetTransactionType() { - throw new PhutilMethodNotImplementedException(); - } - - public function getAlmanacPropertyDeleteTransactionType() { - throw new PhutilMethodNotImplementedException(); - } - - /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacNetwork.php phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacNetwork.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacNetwork.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacNetwork.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,7 +10,6 @@ PhabricatorConduitResultInterface { protected $name; - protected $mailKey; protected $viewPolicy; protected $editPolicy; @@ -25,8 +24,6 @@ self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'sort128', - 'mailKey' => 'bytes20', - ), self::CONFIG_KEY_SCHEMA => array( 'key_name' => array( @@ -37,20 +34,14 @@ ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID(AlmanacNetworkPHIDType::TYPECONST); - } - - public function save() { - if (!$this->mailKey) { - $this->mailKey = Filesystem::readRandomCharacters(20); - } - - return parent::save(); + public function getPHIDType() { + return AlmanacNetworkPHIDType::TYPECONST; } public function getURI() { - return '/almanac/network/'.$this->getID().'/'; + return urisprintf( + '/almanac/network/%s/', + $this->getID()); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacService.php phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacService.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/storage/AlmanacService.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/storage/AlmanacService.php 2022-06-14 16:29:55.000000000 +0000 @@ -14,13 +14,13 @@ protected $name; protected $nameIndex; - protected $mailKey; protected $viewPolicy; protected $editPolicy; protected $serviceType; private $almanacProperties = self::ATTACHABLE; private $bindings = self::ATTACHABLE; + private $activeBindings = self::ATTACHABLE; private $serviceImplementation = self::ATTACHABLE; public static function initializeNewService($type) { @@ -48,7 +48,6 @@ self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'text128', 'nameIndex' => 'bytes12', - 'mailKey' => 'bytes20', 'serviceType' => 'text64', ), self::CONFIG_KEY_SCHEMA => array( @@ -66,8 +65,8 @@ ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID(AlmanacServicePHIDType::TYPECONST); + public function getPHIDType() { + return AlmanacServicePHIDType::TYPECONST; } public function save() { @@ -75,10 +74,6 @@ $this->nameIndex = PhabricatorHash::digestForIndex($this->getName()); - if (!$this->mailKey) { - $this->mailKey = Filesystem::readRandomCharacters(20); - } - return parent::save(); } @@ -91,23 +86,36 @@ } public function getActiveBindings() { - $bindings = $this->getBindings(); + return $this->assertAttached($this->activeBindings); + } - // Filter out disabled bindings. + public function attachBindings(array $bindings) { + $active_bindings = array(); foreach ($bindings as $key => $binding) { + // Filter out disabled bindings. if ($binding->getIsDisabled()) { - unset($bindings[$key]); + continue; } + + // Filter out bindings to disabled devices. + if ($binding->getDevice()->isDisabled()) { + continue; + } + + $active_bindings[$key] = $binding; } - return $bindings; - } + $this->attachActiveBindings($active_bindings); - public function attachBindings(array $bindings) { $this->bindings = $bindings; return $this; } + public function attachActiveBindings(array $bindings) { + $this->activeBindings = $bindings; + return $this; + } + public function getServiceImplementation() { return $this->assertAttached($this->serviceImplementation); } @@ -289,6 +297,9 @@ ->setAttachmentKey('properties'), id(new AlmanacBindingsSearchEngineAttachment()) ->setAttachmentKey('bindings'), + id(new AlmanacBindingsSearchEngineAttachment()) + ->setIsActive(true) + ->setAttachmentKey('activeBindings'), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php phabricator-0~git20220903/phabricator/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php 2022-06-14 16:29:55.000000000 +0000 @@ -46,9 +46,16 @@ $results = array(); foreach ($handles as $handle) { + if ($handle->isClosed()) { + $closed = pht('Disabled'); + } else { + $closed = null; + } + $results[] = id(new PhabricatorTypeaheadResult()) ->setName($handle->getName()) - ->setPHID($handle->getPHID()); + ->setPHID($handle->getPHID()) + ->setClosed($closed); } return $results; diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/util/__tests__/AlmanacNamesTestCase.php phabricator-0~git20220903/phabricator/src/applications/almanac/util/__tests__/AlmanacNamesTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/util/__tests__/AlmanacNamesTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/util/__tests__/AlmanacNamesTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -30,7 +30,7 @@ 'abc' => true, 'a.b' => true, - 'db.phacility.instance' => true, + 'db.companyname.instance' => true, 'web002.useast.example.com' => true, 'master.example-corp.com' => true, diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/view/AlmanacBindingTableView.php phabricator-0~git20220903/phabricator/src/applications/almanac/view/AlmanacBindingTableView.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/view/AlmanacBindingTableView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/view/AlmanacBindingTableView.php 2022-06-14 16:29:55.000000000 +0000 @@ -56,21 +56,41 @@ $icon_active = id(new PHUIIconView()) ->setIcon('fa-check') + ->setColor('green') ->addSigil('has-tooltip') ->setMetadata( array( 'tip' => pht('Active'), )); + $icon_device_disabled = id(new PHUIIconView()) + ->setIcon('fa-times') + ->setColor('grey') + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => pht('Device Disabled'), + )); + $rows = array(); foreach ($bindings as $binding) { $addr = $binding->getInterface()->getAddress(); $port = $binding->getInterface()->getPort(); + $device = $binding->getDevice(); + if ($device->isDisabled()) { + $binding_icon = $icon_device_disabled; + } else if ($binding->getIsDisabled()) { + $binding_icon = $icon_disabled; + } else { + $binding_icon = $icon_active; + } + $rows[] = array( $binding->getID(), - ($binding->getIsDisabled() ? $icon_disabled : $icon_active), + $binding_icon, $handles->renderHandle($binding->getServicePHID()), + $handles->renderHandle($binding->getDevicePHID()), $handles->renderHandle($binding->getInterface()->getNetworkPHID()), $binding->getInterface()->renderDisplayAddress(), diff -Nru phabricator-0~git20200925/phabricator/src/applications/almanac/xaction/AlmanacDeviceStatusTransaction.php phabricator-0~git20220903/phabricator/src/applications/almanac/xaction/AlmanacDeviceStatusTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/almanac/xaction/AlmanacDeviceStatusTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/almanac/xaction/AlmanacDeviceStatusTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,61 @@ +<?php + +final class AlmanacDeviceStatusTransaction + extends AlmanacDeviceTransactionType { + + const TRANSACTIONTYPE = 'almanac:device:status'; + + public function generateOldValue($object) { + return $object->getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + $old_value = $this->getOldValue(); + $new_value = $this->getNewValue(); + + $old_status = AlmanacDeviceStatus::newStatusFromValue($old_value); + $new_status = AlmanacDeviceStatus::newStatusFromValue($new_value); + + $old_name = $old_status->getName(); + $new_name = $new_status->getName(); + + return pht( + '%s changed the status of this device from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old_name), + $this->renderValue($new_name)); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $status_map = AlmanacDeviceStatus::getStatusMap(); + + $old_value = $this->generateOldValue($object); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + + if ($new_value === $old_value) { + continue; + } + + if (!isset($status_map[$new_value])) { + $errors[] = $this->newInvalidError( + pht( + 'Almanac device status "%s" is unrecognized. Valid status '. + 'values are: %s.', + $new_value, + implode(', ', array_keys($status_map))), + $xaction); + continue; + } + } + + return $errors; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/audit/constants/PhabricatorAuditRequestStatus.php phabricator-0~git20220903/phabricator/src/applications/audit/constants/PhabricatorAuditRequestStatus.php --- phabricator-0~git20200925/phabricator/src/applications/audit/constants/PhabricatorAuditRequestStatus.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/audit/constants/PhabricatorAuditRequestStatus.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,89 @@ +<?php + +final class PhabricatorAuditRequestStatus extends Phobject { + + const AUDIT_REQUIRED = 'audit-required'; + const CONCERNED = 'concerned'; + const ACCEPTED = 'accepted'; + const AUDIT_REQUESTED = 'requested'; + const RESIGNED = 'resigned'; + + private $key; + + public static function newForStatus($status) { + $result = new self(); + $result->key = $status; + return $result; + } + + public function getIconIcon() { + return $this->getMapProperty('icon'); + } + + public function getIconColor() { + return $this->getMapProperty('icon.color'); + } + + public function getStatusName() { + $name = $this->getMapProperty('name'); + if ($name !== null) { + return $name; + } + + return pht('Unknown Audit Request Status ("%s")', $this->key); + } + + public function getStatusValue() { + return $this->key; + } + + public function getStatusValueForConduit() { + return $this->getMapProperty('value.conduit'); + } + + public function isResigned() { + return ($this->key === self::RESIGNED); + } + + private function getMapProperty($key, $default = null) { + $map = self::newStatusMap(); + $spec = idx($map, $this->key, array()); + return idx($spec, $key, $default); + } + + private static function newStatusMap() { + return array( + self::AUDIT_REQUIRED => array( + 'name' => pht('Audit Required'), + 'icon' => 'fa-exclamation-circle', + 'icon.color' => 'orange', + 'value.conduit' => 'audit-required', + ), + self::AUDIT_REQUESTED => array( + 'name' => pht('Audit Requested'), + 'icon' => 'fa-exclamation-circle', + 'icon.color' => 'orange', + 'value.conduit' => 'audit-requested', + ), + self::CONCERNED => array( + 'name' => pht('Concern Raised'), + 'icon' => 'fa-times-circle', + 'icon.color' => 'red', + 'value.conduit' => 'concern-raised', + ), + self::ACCEPTED => array( + 'name' => pht('Accepted'), + 'icon' => 'fa-check-circle', + 'icon.color' => 'green', + 'value.conduit' => 'accepted', + ), + self::RESIGNED => array( + 'name' => pht('Resigned'), + 'icon' => 'fa-times', + 'icon.color' => 'grey', + 'value.conduit' => 'resigned', + ), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/audit/constants/PhabricatorAuditStatusConstants.php phabricator-0~git20220903/phabricator/src/applications/audit/constants/PhabricatorAuditStatusConstants.php --- phabricator-0~git20200925/phabricator/src/applications/audit/constants/PhabricatorAuditStatusConstants.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/audit/constants/PhabricatorAuditStatusConstants.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -<?php - -final class PhabricatorAuditStatusConstants extends Phobject { - - const NONE = ''; - const AUDIT_NOT_REQUIRED = 'audit-not-required'; - const AUDIT_REQUIRED = 'audit-required'; - const CONCERNED = 'concerned'; - const ACCEPTED = 'accepted'; - const AUDIT_REQUESTED = 'requested'; - const RESIGNED = 'resigned'; - const CLOSED = 'closed'; - const CC = 'cc'; - - public static function getStatusNameMap() { - $map = array( - self::NONE => pht('Not Applicable'), - self::AUDIT_NOT_REQUIRED => pht('Audit Not Required'), - self::AUDIT_REQUIRED => pht('Audit Required'), - self::CONCERNED => pht('Concern Raised'), - self::ACCEPTED => pht('Accepted'), - self::AUDIT_REQUESTED => pht('Audit Requested'), - self::RESIGNED => pht('Resigned'), - self::CLOSED => pht('Closed'), - self::CC => pht("Was CC'd"), - ); - - return $map; - } - - public static function getActionRequiredStatusConstants() { - return array( - self::AUDIT_REQUIRED, - self::AUDIT_REQUESTED, - ); - } - - public static function getStatusName($code) { - return idx(self::getStatusNameMap(), $code, pht('Unknown')); - } - - public static function getStatusColor($code) { - switch ($code) { - case self::CONCERNED: - $color = 'red'; - break; - case self::AUDIT_REQUIRED: - case self::AUDIT_REQUESTED: - $color = 'orange'; - break; - case self::ACCEPTED: - $color = 'green'; - break; - case self::AUDIT_NOT_REQUIRED: - $color = 'blue'; - break; - case self::RESIGNED: - case self::CLOSED: - $color = 'dark'; - break; - default: - $color = 'bluegrey'; - break; - } - return $color; - } - - public static function getStatusIcon($code) { - switch ($code) { - case self::AUDIT_NOT_REQUIRED: - case self::RESIGNED: - $icon = PHUIStatusItemView::ICON_OPEN; - break; - case self::AUDIT_REQUIRED: - case self::AUDIT_REQUESTED: - $icon = PHUIStatusItemView::ICON_WARNING; - break; - case self::CONCERNED: - $icon = PHUIStatusItemView::ICON_REJECT; - break; - case self::ACCEPTED: - case self::CLOSED: - $icon = PHUIStatusItemView::ICON_ACCEPT; - break; - default: - $icon = PHUIStatusItemView::ICON_QUESTION; - break; - } - return $icon; - } - - public static function getOpenStatusConstants() { - return array( - self::AUDIT_REQUIRED, - self::AUDIT_REQUESTED, - self::CONCERNED, - ); - } - - public static function isOpenStatus($status) { - return in_array($status, self::getOpenStatusConstants()); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/audit/editor/PhabricatorAuditEditor.php phabricator-0~git20220903/phabricator/src/applications/audit/editor/PhabricatorAuditEditor.php --- phabricator-0~git20200925/phabricator/src/applications/audit/editor/PhabricatorAuditEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/audit/editor/PhabricatorAuditEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -178,12 +178,6 @@ } $object->attachAudits($commit->getAudits()); - $status_concerned = PhabricatorAuditStatusConstants::CONCERNED; - $status_closed = PhabricatorAuditStatusConstants::CLOSED; - $status_resigned = PhabricatorAuditStatusConstants::RESIGNED; - $status_accepted = PhabricatorAuditStatusConstants::ACCEPTED; - $status_concerned = PhabricatorAuditStatusConstants::CONCERNED; - $actor_phid = $this->getActingAsPHID(); $actor_is_author = ($object->getAuthorPHID()) && ($actor_phid == $object->getAuthorPHID()); @@ -491,12 +485,6 @@ } foreach ($object->getAudits() as $audit) { - if (!$audit->isInteresting()) { - // Don't send mail to uninteresting auditors, like packages which - // own this code but which audits have not triggered for. - continue; - } - if (!$audit->isResigned()) { $phids[] = $audit->getAuditorPHID(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php phabricator-0~git20220903/phabricator/src/applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -153,13 +153,13 @@ foreach ($commit_audits as $audit) { $audit_id = $audit->getID(); + $status = $audit->getAuditRequestStatusObject(); $description = sprintf( '%10d %-16s %-16s %s: %s', $audit_id, $handles[$audit->getAuditorPHID()]->getName(), - PhabricatorAuditStatusConstants::getStatusName( - $audit->getAuditStatus()), + $status->getStatusName(), $commit->getRepository()->formatCommitName( $commit->getCommitIdentifier()), trim($commit->getSummary())); diff -Nru phabricator-0~git20200925/phabricator/src/applications/audit/query/PhabricatorCommitSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/audit/query/PhabricatorCommitSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/audit/query/PhabricatorCommitSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/audit/query/PhabricatorCommitSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -54,8 +54,8 @@ $query->withUnreachable($map['unreachable']); } - if ($map['unpublished'] !== null) { - $query->withUnpublished($map['unpublished']); + if ($map['permanent'] !== null) { + $query->withPermanent($map['permanent']); } if ($map['ancestorsOf']) { @@ -132,15 +132,15 @@ 'Find or exclude unreachable commits which are not ancestors of '. 'any branch, tag, or ref.')), id(new PhabricatorSearchThreeStateField()) - ->setLabel(pht('Unpublished')) - ->setKey('unpublished') + ->setLabel(pht('Permanent')) + ->setKey('permanent') ->setOptions( pht('(Show All)'), - pht('Show Only Unpublished Commits'), - pht('Hide Unpublished Commits')) + pht('Show Only Permanent Commits'), + pht('Hide Permanent Commits')) ->setDescription( pht( - 'Find or exclude unpublished commits which are not ancestors of '. + 'Find or exclude permanent commits which are ancestors of '. 'any permanent branch, tag, or ref.')), id(new PhabricatorSearchStringListField()) ->setLabel(pht('Ancestors Of')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/adapter/PhutilFacebookAuthAdapter.php phabricator-0~git20220903/phabricator/src/applications/auth/adapter/PhutilFacebookAuthAdapter.php --- phabricator-0~git20200925/phabricator/src/applications/auth/adapter/PhutilFacebookAuthAdapter.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/adapter/PhutilFacebookAuthAdapter.php 2022-06-14 16:29:55.000000000 +0000 @@ -5,13 +5,6 @@ */ final class PhutilFacebookAuthAdapter extends PhutilOAuthAuthAdapter { - private $requireSecureBrowsing; - - public function setRequireSecureBrowsing($require_secure_browsing) { - $this->requireSecureBrowsing = $require_secure_browsing; - return $this; - } - public function getAdapterType() { return 'facebook'; } @@ -61,10 +54,6 @@ return $this->getOAuthAccountData('name'); } - public function getAccountSecuritySettings() { - return $this->getOAuthAccountData('security_settings'); - } - protected function getAuthenticateBaseURI() { return 'https://www.facebook.com/dialog/oauth'; } @@ -79,7 +68,6 @@ 'name', 'email', 'link', - 'security_settings', 'picture', ); @@ -97,17 +85,6 @@ $ex); } - if ($this->requireSecureBrowsing) { - if (empty($data['security_settings']['secure_browsing']['enabled'])) { - throw new Exception( - pht( - 'This Phabricator install requires you to enable Secure Browsing '. - 'on your Facebook account in order to use it to log in to '. - 'Phabricator. For more information, see %s', - 'https://www.facebook.com/help/156201551113407/')); - } - } - return $data; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/adapter/PhutilPhabricatorAuthAdapter.php phabricator-0~git20220903/phabricator/src/applications/auth/adapter/PhutilPhabricatorAuthAdapter.php --- phabricator-0~git20200925/phabricator/src/applications/auth/adapter/PhutilPhabricatorAuthAdapter.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/adapter/PhutilPhabricatorAuthAdapter.php 2022-06-14 16:29:55.000000000 +0000 @@ -89,8 +89,7 @@ } catch (PhutilJSONParserException $ex) { throw new Exception( pht( - 'Expected valid JSON response from Phabricator %s request.', - 'user.whoami'), + 'Expected valid JSON response from "user.whoami" request.'), $ex); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/config/PhabricatorAuthDisableController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/config/PhabricatorAuthDisableController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/config/PhabricatorAuthDisableController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/config/PhabricatorAuthDisableController.php 2022-06-14 16:29:55.000000000 +0000 @@ -49,12 +49,12 @@ if ($config->getShouldAllowRegistration()) { $body = pht( 'Do you want to enable this provider? Users will be able to use '. - 'their existing external accounts to register new Phabricator '. - 'accounts and log in using linked accounts.'); + 'their existing external accounts to register new accounts and '. + 'log in using linked accounts.'); } else { $body = pht( 'Do you want to enable this provider? Users will be able to log '. - 'in to Phabricator using linked accounts.'); + 'in using linked accounts.'); } $button = pht('Enable Provider'); } else { diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/config/PhabricatorAuthEditController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/config/PhabricatorAuthEditController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/config/PhabricatorAuthEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/config/PhabricatorAuthEditController.php 2022-06-14 16:29:55.000000000 +0000 @@ -220,7 +220,7 @@ } else { $registration_warning = pht( "NOTE: Any user who can browse to this install's login page will be ". - "able to register a Phabricator account. To restrict who can register ". + "able to register an account. To restrict who can register ". "an account, configure [[ %s | %s ]].", $config_href, $config_name); @@ -238,10 +238,9 @@ phutil_tag('strong', array(), pht('Allow Registration:')), ' ', pht( - 'Allow users to register new Phabricator accounts using this '. - 'provider. If you disable registration, users can still use this '. - 'provider to log in to existing accounts, but will not be able to '. - 'create new accounts.'), + 'Allow users to register new accounts using this provider. If you '. + 'disable registration, users can still use this provider to log in '. + 'to existing accounts, but will not be able to create new accounts.'), ); $str_link = hsprintf( @@ -249,29 +248,29 @@ pht('Allow Linking Accounts'), pht( 'Allow users to link account credentials for this provider to '. - 'existing Phabricator accounts. There is normally no reason to '. - 'disable this unless you are trying to move away from a provider '. - 'and want to stop users from creating new account links.')); + 'existing accounts. There is normally no reason to disable this '. + 'unless you are trying to move away from a provider and want to '. + 'stop users from creating new account links.')); $str_unlink = hsprintf( '<strong>%s:</strong> %s', pht('Allow Unlinking Accounts'), pht( 'Allow users to unlink account credentials for this provider from '. - 'existing Phabricator accounts. If you disable this, Phabricator '. - 'accounts will be permanently bound to provider accounts.')); + 'existing accounts. If you disable this, accounts will be '. + 'permanently bound to provider accounts.')); $str_trusted_email = hsprintf( '<strong>%s:</strong> %s', pht('Trust Email Addresses'), pht( - 'Phabricator will skip email verification for accounts registered '. + 'Skip email verification for accounts registered '. 'through this provider.')); $str_auto_login = hsprintf( '<strong>%s:</strong> %s', pht('Allow Auto Login'), pht( - 'Phabricator will automatically login with this provider if it is '. + 'Automatically log in with this provider if it is '. 'the only available provider.')); $form = id(new AphrontFormView()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/config/PhabricatorAuthListController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/config/PhabricatorAuthListController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/config/PhabricatorAuthListController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/config/PhabricatorAuthListController.php 2022-06-14 16:29:55.000000000 +0000 @@ -53,8 +53,7 @@ $list->setNoDataString( pht( '%s You have not added authentication providers yet. Use "%s" to add '. - 'a provider, which will let users register new Phabricator accounts '. - 'and log in.', + 'a provider, which will let users register new accounts and log in.', phutil_tag( 'strong', array(), diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/contact/PhabricatorAuthContactNumberTestController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/contact/PhabricatorAuthContactNumberTestController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/contact/PhabricatorAuthContactNumberTestController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/contact/PhabricatorAuthContactNumberTestController.php 2022-06-14 16:29:55.000000000 +0000 @@ -39,7 +39,7 @@ ->setSensitiveContent(false) ->setBody( pht( - 'This is a terse test text message from Phabricator (%s).', + 'This is a terse test text message (from "%s").', $uri->getDomain())) ->save(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthConfirmLinkController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthConfirmLinkController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthConfirmLinkController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthConfirmLinkController.php 2022-06-14 16:29:55.000000000 +0000 @@ -54,8 +54,9 @@ ), pht( 'Confirm the link with this %s account. This account will be '. - 'able to log in to your Phabricator account.', - $provider->getProviderName()))) + 'able to log in to your %s account.', + $provider->getProviderName(), + PlatformSymbols::getPlatformServerName()))) ->appendChild( id(new PhabricatorAuthAccountView()) ->setUser($viewer) diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthController.php 2022-06-14 16:29:55.000000000 +0000 @@ -254,12 +254,16 @@ } $invite_item = id(new PHUIObjectItemView()) - ->setHeader(pht('Welcome to Phabricator!')) + ->setHeader( + pht( + 'Welcome to %s!', + PlatformSymbols::getPlatformServerName())) ->setImageURI($invite_author->getProfileImageURI()) ->addAttribute( pht( - '%s has invited you to join Phabricator.', - $invite_author->getFullName())); + '%s has invited you to join %s.', + $invite_author->getFullName(), + PlatformSymbols::getPlatformServerName())); $invite_list = id(new PHUIObjectItemListView()) ->addItem($invite_item) diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthLinkController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthLinkController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthLinkController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthLinkController.php 2022-06-14 16:29:55.000000000 +0000 @@ -56,8 +56,8 @@ pht('Account Already Linked'), array( pht( - 'Your Phabricator account is already linked to an external '. - 'account for this provider.'), + 'Your account is already linked to an external account for '. + 'this provider.'), )); } break; diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthLoginController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthLoginController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthLoginController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthLoginController.php 2022-06-14 16:29:55.000000000 +0000 @@ -80,9 +80,9 @@ } else { return $this->renderError( pht( - 'The external account ("%s") you just authenticated with is '. - 'not configured to allow logins on this Phabricator install. '. - 'An administrator may have recently disabled it.', + 'The external service ("%s") you just authenticated with is '. + 'not configured to allow logins on this server. An '. + 'administrator may have recently disabled it.', $provider->getProviderName())); } } else if ($viewer->getPHID() == $account->getUserPHID()) { @@ -94,11 +94,14 @@ } else { return $this->renderError( pht( - 'The external account ("%s") you just used to log in is already '. - 'associated with another Phabricator user account. Log in to the '. - 'other Phabricator account and unlink the external account before '. - 'linking it to a new Phabricator account.', - $provider->getProviderName())); + 'The external service ("%s") you just used to log in is already '. + 'associated with another %s user account. Log in to the '. + 'other %s account and unlink the external account before '. + 'linking it to a new %s account.', + $provider->getProviderName(), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName())); } } else { // The account is not yet attached to a Phabricator user, so this is @@ -109,9 +112,9 @@ } else { return $this->renderError( pht( - 'The external account ("%s") you just authenticated with is '. - 'not configured to allow registration on this Phabricator '. - 'install. An administrator may have recently disabled it.', + 'The external service ("%s") you just authenticated with is '. + 'not configured to allow registration on this server. An '. + 'administrator may have recently disabled it.', $provider->getProviderName())); } } else { @@ -135,11 +138,12 @@ if ($existing_accounts) { return $this->renderError( pht( - 'Your Phabricator account is already connected to an external '. - 'account on this provider ("%s"), but you are currently logged '. - 'in to the provider with a different account. Log out of the '. + 'Your %s account is already connected to an external '. + 'account on this service ("%s"), but you are currently logged '. + 'in to the service with a different account. Log out of the '. 'external service, then log back in with the correct account '. 'before refreshing the account link.', + PlatformSymbols::getPlatformServerName(), $provider->getProviderName())); } @@ -148,9 +152,9 @@ } else { return $this->renderError( pht( - 'The external account ("%s") you just authenticated with is '. - 'not configured to allow account linking on this Phabricator '. - 'install. An administrator may have recently disabled it.', + 'The external service ("%s") you just authenticated with is '. + 'not configured to allow account linking on this server. An '. + 'administrator may have recently disabled it.', $provider->getProviderName())); } } @@ -169,7 +173,8 @@ return $this->renderError( pht( 'The external account you just logged in with is not associated '. - 'with a valid Phabricator user.')); + 'with a valid %s user account.', + PlatformSymbols::getPlatformServerName())); } return $this->loginUser($user); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php 2022-06-14 16:29:55.000000000 +0000 @@ -202,7 +202,7 @@ $messages = array(); $messages[] = pht( - 'Before you can use Phabricator, you need to add multi-factor '. + 'Before you can use this software, you need to add multi-factor '. 'authentication to your account. Multi-factor authentication helps '. 'secure your account by making it more difficult for attackers to '. 'gain access or take sensitive actions.'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php 2022-06-14 16:29:55.000000000 +0000 @@ -151,7 +151,9 @@ switch ($link_type) { case PhabricatorAuthSessionEngine::ONETIME_WELCOME: - $title = pht('Welcome to Phabricator'); + $title = pht( + 'Welcome to %s', + PlatformSymbols::getPlatformServerName()); break; case PhabricatorAuthSessionEngine::ONETIME_RECOVER: $title = pht('Account Recovery'); @@ -159,7 +161,9 @@ case PhabricatorAuthSessionEngine::ONETIME_USERNAME: case PhabricatorAuthSessionEngine::ONETIME_RESET: default: - $title = pht('Log in to Phabricator'); + $title = pht( + 'Log in to %s', + PlatformSymbols::getPlatformServerName()); break; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthRegisterController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthRegisterController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthRegisterController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthRegisterController.php 2022-06-14 16:29:55.000000000 +0000 @@ -83,8 +83,8 @@ if (!PhabricatorUserEmail::isValidAddress($default_email)) { $errors[] = pht( 'The email address associated with this external account ("%s") is '. - 'not a valid email address and can not be used to register a '. - 'Phabricator account. Choose a different, valid address.', + 'not a valid email address and can not be used to register an '. + 'account. Choose a different, valid address.', phutil_tag('strong', array(), $default_email)); $default_email = null; } @@ -102,8 +102,7 @@ $errors[] = pht( 'The email address associated with this account ("%s") is '. 'already in use by an application and can not be used to '. - 'register a new Phabricator account. Choose a different, valid '. - 'address.', + 'register a new account. Choose a different, valid address.', phutil_tag('strong', array(), $default_email)); $default_email = null; } @@ -122,8 +121,8 @@ array( pht( 'The account you are attempting to register with has an invalid '. - 'email address (%s). This Phabricator install only allows '. - 'registration with specific email addresses:', + 'email address (%s). This server only allows registration with '. + 'specific email addresses:', $debug_email), phutil_tag('br'), phutil_tag('br'), @@ -157,16 +156,17 @@ ->addHiddenInput('phase', 1) ->appendParagraph( pht( - 'You are creating a new Phabricator account linked to an '. - 'existing external account from outside Phabricator.')) + 'You are creating a new account linked to an existing '. + 'external account.')) ->appendParagraph( pht( 'The email address ("%s") associated with the external account '. - 'is already in use by an existing Phabricator account. Multiple '. - 'Phabricator accounts may not have the same email address, so '. - 'you can not use this email address to register a new '. - 'Phabricator account.', - phutil_tag('strong', array(), $show_existing))) + 'is already in use by an existing %s account. Multiple '. + '%s accounts may not have the same email address, so '. + 'you can not use this email address to register a new account.', + phutil_tag('strong', array(), $show_existing), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName())) ->appendParagraph( pht( 'If you want to register a new account, continue with this '. @@ -174,10 +174,11 @@ 'for the new account.')) ->appendParagraph( pht( - 'If you want to link an existing Phabricator account to this '. + 'If you want to link an existing %s account to this '. 'external account, do not continue. Instead: log in to your '. 'existing account, then go to "Settings" and link the account '. - 'in the "External Accounts" panel.')) + 'in the "External Accounts" panel.', + PlatformSymbols::getPlatformServerName())) ->appendParagraph( pht( 'If you continue, you will create a new account. You will not '. @@ -187,10 +188,10 @@ } else { $errors[] = pht( 'The external account you are registering with has an email address '. - 'that is already in use ("%s") by an existing Phabricator account. '. - 'Choose a new, valid email address to register a new Phabricator '. - 'account.', - phutil_tag('strong', array(), $show_existing)); + 'that is already in use ("%s") by an existing %s account. '. + 'Choose a new, valid email address to register a new account.', + phutil_tag('strong', array(), $show_existing), + PlatformSymbols::getPlatformServerName()); } } @@ -595,7 +596,9 @@ if ($is_setup) { $crumbs->addTextCrumb(pht('Setup Admin Account')); - $title = pht('Welcome to Phabricator'); + $title = pht( + 'Welcome to %s', + PlatformSymbols::getPlatformServerName()); } else { $crumbs->addTextCrumb(pht('Register')); $crumbs->addTextCrumb($provider->getProviderName()); @@ -607,7 +610,10 @@ if ($is_setup) { $welcome_view = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) - ->setTitle(pht('Welcome to Phabricator')) + ->setTitle( + pht( + 'Welcome to %s', + PlatformSymbols::getPlatformServerName())) ->appendChild( pht( 'Installation is complete. Register your administrator account '. @@ -710,8 +716,9 @@ } private function sendWaitingForApprovalEmail(PhabricatorUser $user) { - $title = '[Phabricator] '.pht( - 'New User "%s" Awaiting Approval', + $title = pht( + '[%s] New User "%s" Awaiting Approval', + PlatformSymbols::getPlatformServerName(), $user->getUsername()); $body = new PhabricatorMetaMTAMailBody(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthSetExternalController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthSetExternalController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthSetExternalController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthSetExternalController.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,10 +42,11 @@ PhabricatorAuthLinkMessageType::MESSAGEKEY); if (!strlen($text)) { $text = pht( - 'You can link your Phabricator account to an external account to '. + 'You can link your %s account to an external account to '. 'allow you to log in more easily in the future. To continue, choose '. 'an account to link below. If you prefer not to link your account, '. - 'you can skip this step.'); + 'you can skip this step.', + PlatformSymbols::getPlatformServerName()); } $remarkup_view = new PHUIRemarkupView($viewer, $text); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php 2022-06-14 16:29:55.000000000 +0000 @@ -105,7 +105,7 @@ 'This workflow will generate a new SSH keypair, add the public '. 'key, and let you download the private key.')) ->appendParagraph( - pht('Phabricator will not retain a copy of the private key.')) + pht('The private key will not be retained.')) ->addSubmitButton(pht('Generate New Keypair')) ->addCancelButton($cancel_uri); } catch (Exception $ex) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthStartController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthStartController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthStartController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthStartController.php 2022-06-14 16:29:55.000000000 +0000 @@ -90,11 +90,11 @@ return $this->renderError( pht( - 'This Phabricator install is not configured with any enabled '. - 'authentication providers which can be used to log in. If you '. - 'have accidentally locked yourself out by disabling all providers, '. - 'you can use `%s` to recover access to an account.', - 'phabricator/bin/auth recover <username>')); + 'This server is not configured with any enabled authentication '. + 'providers which can be used to log in. If you have accidentally '. + 'locked yourself out by disabling all providers, you can use `%s` '. + 'to recover access to an account.', + './bin/auth recover <username>')); } $next_uri = $request->getStr('next'); @@ -252,7 +252,7 @@ $message = pht( 'ERROR: You are making a Conduit API request to "%s", but the correct '. - 'HTTP request path to use in order to access a COnduit method is "%s" '. + 'HTTP request path to use in order to access a Conduit method is "%s" '. '(for example, "%s"). Check your configuration.', $request_path, $conduit_path, diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthUnlinkController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthUnlinkController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorAuthUnlinkController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorAuthUnlinkController.php 2022-06-14 16:29:55.000000000 +0000 @@ -86,7 +86,7 @@ ->appendChild( pht( 'You can not unlink this account because the administrator has '. - 'configured Phabricator to make links to "%s" accounts permanent.', + 'configured this server to make links to "%s" accounts permanent.', $provider->getProviderName())) ->addCancelButton($done_uri); } @@ -123,7 +123,7 @@ $title = pht('Unlink "%s" Account?', $provider->getProviderName()); $body = pht( 'You will no longer be able to use your %s account to '. - 'log in to Phabricator.', + 'log in.', $provider->getProviderName()); return $this->newDialog() diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorEmailVerificationController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorEmailVerificationController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorEmailVerificationController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorEmailVerificationController.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,7 +44,7 @@ $title = pht('Address Already Verified'); $content = pht( 'This email address has already been verified.'); - $continue = pht('Continue to Phabricator'); + $continue = pht('Continue'); } else if ($request->isFormPost()) { id(new PhabricatorUserEditor()) @@ -55,7 +55,7 @@ $content = pht( 'The email address %s is now verified.', phutil_tag('strong', array(), $email->getAddress())); - $continue = pht('Continue to Phabricator'); + $continue = pht('Continue'); } else { $title = pht('Verify Email Address'); $content = pht( diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php --- phabricator-0~git20200925/phabricator/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/controller/PhabricatorMustVerifyEmailController.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,8 +34,7 @@ $must_verify = pht( 'You must verify your email address to log in. You should have a '. - 'new email message from Phabricator with verification instructions '. - 'in your inbox (%s).', + 'new email message with verification instructions in your inbox (%s).', phutil_tag('strong', array(), $email_address)); $send_again = pht( diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/engine/PhabricatorAuthPasswordEngine.php phabricator-0~git20220903/phabricator/src/applications/auth/engine/PhabricatorAuthPasswordEngine.php --- phabricator-0~git20200925/phabricator/src/applications/auth/engine/PhabricatorAuthPasswordEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/engine/PhabricatorAuthPasswordEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -181,6 +181,12 @@ $normal_password = phutil_utf8_strtolower($raw_password); if (strlen($normal_password) >= $minimum_similarity) { foreach ($normal_map as $term => $source) { + + // See T2312. This may be required if the term list includes numeric + // strings like "12345", which will be cast to integers when used as + // array keys. + $term = phutil_string_cast($term); + if (strpos($term, $normal_password) === false && strpos($normal_password, $term) === false) { continue; diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php phabricator-0~git20220903/phabricator/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php --- phabricator-0~git20200925/phabricator/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -39,7 +39,13 @@ private function buildLoginMenu() { $controller = $this->getController(); - $uri = new PhutilURI('/auth/start/'); + // See T13636. This button may be rendered by the 404 controller on sites + // other than the primary PlatformSite. Link the button to the primary + // site. + + $uri = '/auth/start/'; + $uri = PhabricatorEnv::getURI($uri); + $uri = new PhutilURI($uri); if ($controller) { $path = $controller->getRequest()->getPath(); $uri->replaceQueryParam('next', $path); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/factor/PhabricatorDuoAuthFactor.php phabricator-0~git20220903/phabricator/src/applications/auth/factor/PhabricatorDuoAuthFactor.php --- phabricator-0~git20200925/phabricator/src/applications/auth/factor/PhabricatorDuoAuthFactor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/factor/PhabricatorDuoAuthFactor.php 2022-06-14 16:29:55.000000000 +0000 @@ -133,7 +133,9 @@ ->setTransactionType($xaction_usernames) ->setOptions( array( - 'username' => pht('Use Phabricator Username'), + 'username' => pht( + 'Use %s Username', + PlatformSymbols::getPlatformServerName()), 'email' => pht('Use Primary Email Address'), )), id(new PhabricatorSelectEditField()) @@ -510,7 +512,7 @@ ->setIsError(true) ->setErrorMessage( pht( - 'This factor has been removed from your device, so Phabricator '. + 'This factor has been removed from your device, so this server '. 'can not send you a challenge. To continue, an administrator '. 'must strip this factor from your account.')); } @@ -547,7 +549,7 @@ // The Duo push timeout is 60 seconds. Set our challenge to expire slightly // more quickly so that we'll re-issue a new challenge before Duo times out. // This should keep users away from a dead-end where they can't respond to - // Duo but Phabricator won't issue a new challenge yet. + // Duo but we won't issue a new challenge yet. $ttl_seconds = 55; return array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/factor/PhabricatorSMSAuthFactor.php phabricator-0~git20220903/phabricator/src/applications/auth/factor/PhabricatorSMSAuthFactor.php --- phabricator-0~git20200925/phabricator/src/applications/auth/factor/PhabricatorSMSAuthFactor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/factor/PhabricatorSMSAuthFactor.php 2022-06-14 16:29:55.000000000 +0000 @@ -388,7 +388,8 @@ ->setSensitiveContent(true) ->setBody( pht( - 'Phabricator (%s) MFA Code: %s', + '%s (%s) MFA Code: %s', + PlatformSymbols::getPlatformServerName(), $this->getInstallDisplayName(), $envelope->openEnvelope())) ->save(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/guidance/PhabricatorAuthProvidersGuidanceEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,7 +42,7 @@ if ($domains_value) { $message = pht( - 'Phabricator is configured with an email domain whitelist (in %s), so '. + 'This server is configured with an email domain whitelist (in %s), so '. 'only users with a verified email address at one of these %s '. 'allowed domain(s) will be able to register an account: %s', $domains_link, @@ -53,7 +53,7 @@ ->setMessage($message); } else { $message = pht( - 'Anyone who can browse to this Phabricator install will be able to '. + 'Anyone who can browse to this this server will be able to '. 'register an account. To add email domain restrictions, configure '. '%s.', $domains_link); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,8 +9,7 @@ ->setExamples('**recover** __username__') ->setSynopsis( pht( - 'Recover access to an account if you have locked yourself out '. - 'of Phabricator.')) + 'Recover access to an account if you have locked yourself out.')) ->setArguments( array( array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -60,7 +60,7 @@ $type = $args->getArg('type'); $is_everything = $args->getArg('everything'); - if (!strlen($type) && !$is_everything) { + if ($type === null && !$is_everything) { if ($is_list) { // By default, "bin/revoke --list" implies "--everything". $types = $all_types; @@ -94,7 +94,7 @@ $from = $args->getArg('from'); if ($is_list) { - if (strlen($from) || $is_everywhere) { + if ($from !== null || $is_everywhere) { throw new PhutilArgumentUsageException( pht( 'You can not "--list" and revoke credentials (with "--from" or '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,9 +9,9 @@ ->setExamples('**trust-oauth-client** [--id client_id]') ->setSynopsis( pht( - 'Set Phabricator to trust an OAuth client. Phabricator '. - 'redirects to trusted OAuth clients that users have authorized '. - 'without user intervention.')) + 'Mark an OAuth client as trusted. Trusted OAuth clients may be '. + 'reauthorized without requiring users to manually confirm the '. + 'action.')) ->setArguments( array( array( @@ -28,8 +28,7 @@ if (!$id) { throw new PhutilArgumentUsageException( pht( - 'Specify an OAuth client id with %s.', - '--id')); + 'Specify an OAuth client id with "--id".')); } $client = id(new PhabricatorOAuthServerClientQuery()) @@ -46,7 +45,7 @@ if ($client->getIsTrusted()) { throw new PhutilArgumentUsageException( pht( - 'Phabricator already trusts OAuth client "%s".', + 'OAuth client "%s" is already trusted.', $client->getName())); } @@ -57,7 +56,7 @@ $console->writeOut( "%s\n", pht( - 'Updated; Phabricator trusts OAuth client %s.', + 'OAuth client "%s" is now trusted.', $client->getName())); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,9 +9,8 @@ ->setExamples('**untrust-oauth-client** [--id client_id]') ->setSynopsis( pht( - 'Set Phabricator to not trust an OAuth client. Phabricator '. - 'redirects to trusted OAuth clients that users have authorized '. - 'without user intervention.')) + 'Remove trust from an OAuth client. Users must manually confirm '. + 'reauthorization of untrusted OAuth clients.')) ->setArguments( array( array( @@ -46,7 +45,7 @@ if (!$client->getIsTrusted()) { throw new PhutilArgumentUsageException( pht( - 'Phabricator already does not trust OAuth client "%s".', + 'OAuth client "%s" is already untrusted.', $client->getName())); } @@ -57,7 +56,7 @@ $console->writeOut( "%s\n", pht( - 'Updated; Phabricator does not trust OAuth client %s.', + 'OAuth client "%s" is now trusted.', $client->getName())); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorAmazonAuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorAmazonAuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorAmazonAuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorAmazonAuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -14,7 +14,7 @@ $https_note = null; if ($uri->getProtocol() !== 'https') { $https_note = pht( - 'NOTE: Amazon **requires** HTTPS, but your Phabricator install does '. + 'NOTE: Amazon **requires** HTTPS, but this service does '. 'not use HTTPS. **You will not be able to add Amazon as an '. 'authentication provider until you configure HTTPS on this install**.'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorFacebookAuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorFacebookAuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorFacebookAuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorFacebookAuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -3,14 +3,35 @@ final class PhabricatorFacebookAuthProvider extends PhabricatorOAuth2AuthProvider { - const KEY_REQUIRE_SECURE = 'oauth:facebook:require-secure'; - public function getProviderName() { return pht('Facebook'); } protected function getProviderConfigurationHelp() { $uri = PhabricatorEnv::getProductionURI($this->getLoginURI()); + + $domain = id(new PhutilURI($uri))->getDomain(); + + $table = array( + 'Client OAuth Login' => pht('No'), + 'Web OAuth Login' => pht('Yes'), + 'Enforce HTTPS' => pht('Yes'), + 'Force Web OAuth Reauthentication' => pht('Yes (Optional)'), + 'Embedded Browser OAuth Login' => pht('No'), + 'Use Strict Mode for Redirect URIs' => pht('Yes'), + 'Login from Devices' => pht('No'), + 'Valid OAuth Redirect URIs' => '`'.(string)$uri.'`', + 'App Domains' => '`'.$domain.'`', + ); + + $rows = array(); + foreach ($table as $k => $v) { + $rows[] = sprintf('| %s | %s |', $k, $v); + $rows[] = sprintf('|----| |'); + } + $rows = implode("\n", $rows); + + return pht( 'To configure Facebook OAuth, create a new Facebook Application here:'. "\n\n". @@ -18,29 +39,15 @@ "\n\n". 'You should use these settings in your application:'. "\n\n". - " - **Site URL**: Set this to `%s`\n". - " - **Valid OAuth redirect URIs**: You should also set this to `%s`\n". - " - **Client OAuth Login**: Set this to **OFF**.\n". - " - **Embedded browser OAuth Login**: Set this to **OFF**.\n". + "%s\n". "\n\n". - "Some of these settings may be in the **Advanced** tab.\n\n". "After creating your new application, copy the **App ID** and ". "**App Secret** to the fields above.", - (string)$uri, - (string)$uri); - } - - public function getDefaultProviderConfig() { - return parent::getDefaultProviderConfig() - ->setProperty(self::KEY_REQUIRE_SECURE, 1); + $rows); } protected function newOAuthAdapter() { - $require_secure = $this->getProviderConfig()->getProperty( - self::KEY_REQUIRE_SECURE); - - return id(new PhutilFacebookAuthAdapter()) - ->setRequireSecureBrowsing($require_secure); + return new PhutilFacebookAuthAdapter(); } protected function getLoginIcon() { @@ -55,71 +62,4 @@ ); } - public function readFormValuesFromProvider() { - $require_secure = $this->getProviderConfig()->getProperty( - self::KEY_REQUIRE_SECURE); - - return parent::readFormValuesFromProvider() + array( - self::KEY_REQUIRE_SECURE => $require_secure, - ); - } - - public function readFormValuesFromRequest(AphrontRequest $request) { - return parent::readFormValuesFromRequest($request) + array( - self::KEY_REQUIRE_SECURE => $request->getBool(self::KEY_REQUIRE_SECURE), - ); - } - - public function extendEditForm( - AphrontRequest $request, - AphrontFormView $form, - array $values, - array $issues) { - - parent::extendEditForm($request, $form, $values, $issues); - - $key_require = self::KEY_REQUIRE_SECURE; - $v_require = idx($values, $key_require); - - $form - ->appendChild( - id(new AphrontFormCheckboxControl()) - ->addCheckbox( - $key_require, - $v_require, - pht( - "%s ". - "Require users to enable 'secure browsing' on Facebook in order ". - "to use Facebook to authenticate with Phabricator. This ". - "improves security by preventing an attacker from capturing ". - "an insecure Facebook session and escalating it into a ". - "Phabricator session. Enabling it is recommended.", - phutil_tag('strong', array(), pht('Require Secure Browsing:'))))); - } - - public function renderConfigPropertyTransactionTitle( - PhabricatorAuthProviderConfigTransaction $xaction) { - - $author_phid = $xaction->getAuthorPHID(); - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - $key = $xaction->getMetadataValue( - PhabricatorAuthProviderConfigTransaction::PROPERTY_KEY); - - switch ($key) { - case self::KEY_REQUIRE_SECURE: - if ($new) { - return pht( - '%s turned "Require Secure Browsing" on.', - $xaction->renderHandleLink($author_phid)); - } else { - return pht( - '%s turned "Require Secure Browsing" off.', - $xaction->renderHandleLink($author_phid)); - } - } - - return parent::renderConfigPropertyTransactionTitle($xaction); - } - } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorGitHubAuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorGitHubAuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorGitHubAuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorGitHubAuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -19,7 +19,7 @@ "You should use these settings in your application:". "\n\n". " - **URL:** Set this to your full domain with protocol. For this ". - " Phabricator install, the correct value is: `%s`\n". + " server, the correct value is: `%s`\n". " - **Callback URL**: Set this to: `%s`\n". "\n\n". "Once you've created an application, copy the **Client ID** and ". diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorJIRAAuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -31,7 +31,7 @@ "settings to create an application:\n\n". " - **Server URL**: `%s`\n". " - Then, click **Next**. On the second page:\n". - " - **Application Name**: `Phabricator`\n". + " - **Application Name**: `%s`\n". " - **Application Type**: `Generic Application`\n". " - Then, click **Create**.\n\n". "**Configure Your Application**: Find the application you just ". @@ -41,13 +41,15 @@ "settings:\n\n". " - **Consumer Key**: Set this to the \"Consumer Key\" value in the ". "form above.\n". - " - **Consumer Name**: `Phabricator`\n". + " - **Consumer Name**: `%s`\n". " - **Public Key**: Set this to the \"Public Key\" value in the ". "form above.\n". " - **Consumer Callback URL**: `%s`\n". "Click **Save** in JIRA. Authentication should now be configured, ". "and this provider should work correctly.", PhabricatorEnv::getProductionURI('/'), + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName(), $login_uri); } } @@ -169,7 +171,7 @@ "The PHP 'openssl' extension is not installed. You must install ". "this extension in order to add a JIRA authentication provider, ". "because JIRA OAuth requests use the RSA-SHA1 signing algorithm. ". - "Install the 'openssl' extension, restart Phabricator, and try ". + "Install the 'openssl' extension, restart everything, and try ". "again.")); } @@ -198,8 +200,8 @@ ->appendRemarkupInstructions( pht( "**JIRA Instance Name**\n\n". - "Choose a permanent name for this instance of JIRA. Phabricator ". - "uses this name internally to keep track of this instance of ". + "Choose a permanent name for this instance of JIRA. This name is ". + "used internally to keep track of this particular instance of ". "JIRA, in case the URL changes later.\n\n". "Use lowercase letters, digits, and period. For example, ". "`jira`, `jira.mycompany` or `jira.engineering` are reasonable ". @@ -281,8 +283,7 @@ new PHUIRemarkupView( $viewer, pht( - '**Post a comment** in the JIRA task, similar to the '. - 'emails Phabricator sends.')), + '**Post a comment** in the JIRA task.')), $this->shouldCreateJIRAComment())); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorLDAPAuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,7 +11,7 @@ public function getDescriptionForCreate() { return pht( 'Configure a connection to an LDAP server so that users can use their '. - 'LDAP credentials to log in to Phabricator.'); + 'LDAP credentials to log in.'); } public function getDefaultProviderConfig() { @@ -312,8 +312,8 @@ $instructions = array( self::KEY_SEARCH_ATTRIBUTES => pht( - "When a user types their LDAP username and password into Phabricator, ". - "Phabricator can either bind to LDAP with those credentials directly ". + "When a user provides their LDAP username and password, this ". + "software can either bind to LDAP with those credentials directly ". "(which is simpler, but not as powerful) or bind to LDAP with ". "anonymous credentials, then search for record matching the supplied ". "credentials (which is more complicated, but more powerful).\n\n". diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorOAuth1AuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorOAuth1AuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorOAuth1AuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorOAuth1AuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ $config = $this->getProviderConfig(); $adapter->setConsumerKey($config->getProperty(self::PROPERTY_CONSUMER_KEY)); $secret = $config->getProperty(self::PROPERTY_CONSUMER_SECRET); - if (strlen($secret)) { + if (phutil_nonempty_string($secret)) { $adapter->setConsumerSecret(new PhutilOpaqueEnvelope($secret)); } $adapter->setCallbackURI(PhabricatorEnv::getURI($this->getLoginURI())); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorPhabricatorAuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,17 +7,16 @@ const PROPERTY_PHABRICATOR_URI = 'oauth2:phabricator:uri'; public function getProviderName() { - return pht('Phabricator'); + return PlatformSymbols::getPlatformServerName(); } public function getConfigurationHelp() { if ($this->isCreate()) { return pht( - "**Step 1 of 2 - Name Phabricator OAuth Instance**\n\n". - 'Choose a permanent name for the OAuth server instance of '. - 'Phabricator. //This// instance of Phabricator uses this name '. - 'internally to keep track of the OAuth server instance of '. - 'Phabricator, in case the URL changes later.'); + "**Step 1 of 2 - Name Remote Server**\n\n". + 'Choose a permanent name for the remote server you want to connect '. + 'to. This name is used internally to keep track of the remote '. + 'server, in case the URL changes later.'); } return parent::getConfigurationHelp(); @@ -29,8 +28,8 @@ $login_uri = PhabricatorEnv::getURI($this->getLoginURI()); return pht( - "**Step 2 of 2 - Configure Phabricator OAuth Instance**\n\n". - "To configure Phabricator OAuth, create a new application here:". + "**Step 2 of 2 - Configure OAuth Server**\n\n". + "To configure OAuth, create a new application here:". "\n\n". "%s/oauthserver/client/create/". "\n\n". @@ -54,7 +53,7 @@ } protected function getLoginIcon() { - return 'Phabricator'; + return PlatformSymbols::getPlatformServerName(); } private function isCreate() { @@ -106,23 +105,23 @@ $key_uri = self::PROPERTY_PHABRICATOR_URI; if (!strlen($values[$key_name])) { - $errors[] = pht('Phabricator instance name is required.'); + $errors[] = pht('Server name is required.'); $issues[$key_name] = pht('Required'); } else if (!preg_match('/^[a-z0-9.]+\z/', $values[$key_name])) { $errors[] = pht( - 'Phabricator instance name must contain only lowercase letters, '. + 'Server name must contain only lowercase letters, '. 'digits, and periods.'); $issues[$key_name] = pht('Invalid'); } if (!strlen($values[$key_uri])) { - $errors[] = pht('Phabricator base URI is required.'); + $errors[] = pht('Base URI is required.'); $issues[$key_uri] = pht('Required'); } else { $uri = new PhutilURI($values[$key_uri]); if (!$uri->getProtocol()) { $errors[] = pht( - 'Phabricator base URI should include protocol (like "%s").', + 'Base URI should include protocol (like "%s").', 'https://'); $issues[$key_uri] = pht('Invalid'); } @@ -161,7 +160,7 @@ $form ->appendChild( id(new AphrontFormTextControl()) - ->setLabel(pht('Phabricator Instance Name')) + ->setLabel(pht('Server Name')) ->setValue($v_name) ->setName(self::PROPERTY_PHABRICATOR_NAME) ->setError($e_name) @@ -170,26 +169,25 @@ phutil_tag( 'tt', array(), - '`phabricator.oauthserver`')))); + '`example.oauthserver`')))); } else { $form ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel(pht('Phabricator Instance Name')) + ->setLabel(pht('Server Name')) ->setValue($v_name)); } $form ->appendChild( id(new AphrontFormTextControl()) - ->setLabel(pht('Phabricator Base URI')) + ->setLabel(pht('Base URI')) ->setValue($v_uri) ->setName(self::PROPERTY_PHABRICATOR_URI) ->setCaption( pht( - 'The URI where the OAuth server instance of Phabricator is '. - 'installed. For example: %s', - phutil_tag('tt', array(), 'https://phabricator.mycompany.com/'))) + 'The URI where the OAuth server is installed. For example: %s', + phutil_tag('tt', array(), 'https://devtools.example.com/'))) ->setError($e_uri)); if (!$is_setup) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorWordPressAuthProvider.php phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorWordPressAuthProvider.php --- phabricator-0~git20200925/phabricator/src/applications/auth/provider/PhabricatorWordPressAuthProvider.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/provider/PhabricatorWordPressAuthProvider.php 2022-06-14 16:29:55.000000000 +0000 @@ -19,7 +19,7 @@ "You should use these settings in your application:". "\n\n". " - **URL:** Set this to your full domain with protocol. For this ". - " Phabricator install, the correct value is: `%s`\n". + " server, the correct value is: `%s`\n". " - **Redirect URL**: Set this to: `%s`\n". "\n\n". "Once you've created an application, copy the **Client ID** and ". diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthChallengeQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthChallengeQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthChallengeQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthChallengeQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,10 +40,6 @@ return new PhabricatorAuthChallenge(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthContactNumberQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthContactNumberQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthContactNumberQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthContactNumberQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,10 +44,6 @@ return new PhabricatorAuthContactNumber(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthFactorConfigQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthFactorConfigQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthFactorConfigQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthFactorConfigQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorAuthFactorConfig(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthFactorProviderQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhabricatorAuthFactorProvider(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthMessageQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthMessageQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthMessageQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthMessageQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorAuthMessage(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthPasswordQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthPasswordQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthPasswordQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthPasswordQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorAuthPassword(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthProviderConfigQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthProviderConfigQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthProviderConfigQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthProviderConfigQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhabricatorAuthProviderConfig(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthSessionQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthSessionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthSessionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthSessionQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorAuthSession(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $sessions) { $identity_phids = mpull($sessions, 'getUserPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -47,10 +47,6 @@ return new PhabricatorAuthSSHKey(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $keys) { $object_phids = mpull($keys, 'getObjectPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,10 +44,6 @@ return new PhabricatorAuthTemporaryToken(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorExternalAccountIdentifierQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorExternalAccountIdentifierQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorExternalAccountIdentifierQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorExternalAccountIdentifierQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorExternalAccountIdentifier(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorExternalAccountQuery.php phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorExternalAccountQuery.php --- phabricator-0~git20200925/phabricator/src/applications/auth/query/PhabricatorExternalAccountQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/query/PhabricatorExternalAccountQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -66,10 +66,6 @@ return new PhabricatorExternalAccount(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $accounts) { $viewer = $this->getViewer(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/auth/worker/PhabricatorAuthInviteWorker.php phabricator-0~git20220903/phabricator/src/applications/auth/worker/PhabricatorAuthInviteWorker.php --- phabricator-0~git20200925/phabricator/src/applications/auth/worker/PhabricatorAuthInviteWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/auth/worker/PhabricatorAuthInviteWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -51,8 +51,10 @@ ->setForceDelivery(true) ->setSubject( pht( - '[Phabricator] %s has invited you to join Phabricator', - $author->getFullName())) + '[%s] %s has invited you to join %s', + PlatformSymbols::getPlatformServerName(), + $author->getFullName(), + PlatformSymbols::getPlatformServerName())) ->setBody($template) ->saveAndSend(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/badges/query/PhabricatorBadgesAwardQuery.php phabricator-0~git20220903/phabricator/src/applications/badges/query/PhabricatorBadgesAwardQuery.php --- phabricator-0~git20200925/phabricator/src/applications/badges/query/PhabricatorBadgesAwardQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/badges/query/PhabricatorBadgesAwardQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -57,10 +57,6 @@ return (bool)$this->badgeStatuses; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - public function newResultObject() { return new PhabricatorBadgesAward(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/badges/query/PhabricatorBadgesQuery.php phabricator-0~git20220903/phabricator/src/applications/badges/query/PhabricatorBadgesQuery.php --- phabricator-0~git20200925/phabricator/src/applications/badges/query/PhabricatorBadgesQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/badges/query/PhabricatorBadgesQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,10 +34,6 @@ $ngrams); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function getPrimaryTableAlias() { return 'badges'; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/base/controller/Phabricator404Controller.php phabricator-0~git20220903/phabricator/src/applications/base/controller/Phabricator404Controller.php --- phabricator-0~git20200925/phabricator/src/applications/base/controller/Phabricator404Controller.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/base/controller/Phabricator404Controller.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,11 @@ <?php -final class Phabricator404Controller extends PhabricatorController { +final class Phabricator404Controller + extends PhabricatorController { + + public function shouldRequireLogin() { + return false; + } public function processRequest() { return new Aphront404Response(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/base/controller/PhabricatorController.php phabricator-0~git20220903/phabricator/src/applications/base/controller/PhabricatorController.php --- phabricator-0~git20200925/phabricator/src/applications/base/controller/PhabricatorController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/base/controller/PhabricatorController.php 2022-06-14 16:29:55.000000000 +0000 @@ -420,6 +420,10 @@ ->setSubmitURI($submit_uri); } + public function newRedirect() { + return id(new AphrontRedirectResponse()); + } + public function newPage() { $page = id(new PhabricatorStandardPageView()) ->setRequest($this->getRequest()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/base/controller/PhabricatorPlatform404Controller.php phabricator-0~git20220903/phabricator/src/applications/base/controller/PhabricatorPlatform404Controller.php --- phabricator-0~git20200925/phabricator/src/applications/base/controller/PhabricatorPlatform404Controller.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/base/controller/PhabricatorPlatform404Controller.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,10 @@ +<?php + +final class PhabricatorPlatform404Controller + extends PhabricatorController { + + public function processRequest() { + return new Aphront404Response(); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/base/PhabricatorApplication.php phabricator-0~git20220903/phabricator/src/applications/base/PhabricatorApplication.php --- phabricator-0~git20200925/phabricator/src/applications/base/PhabricatorApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/base/PhabricatorApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -135,10 +135,9 @@ /** - * Returns true if an application is first-party (developed by Phacility) - * and false otherwise. + * Returns true if an application is first-party and false otherwise. * - * @return bool True if this application is developed by Phacility. + * @return bool True if this application is first-party. */ final public function isFirstParty() { $where = id(new ReflectionClass($this))->getFileName(); @@ -490,7 +489,7 @@ return array(); } - final private function getCustomPolicySetting($capability) { + private function getCustomPolicySetting($capability) { if (!$this->isCapabilityEditable($capability)) { return null; } @@ -516,7 +515,7 @@ } - final private function getCustomCapabilitySpecification($capability) { + private function getCustomCapabilitySpecification($capability) { $custom = $this->getCustomCapabilities(); if (!isset($custom[$capability])) { throw new Exception(pht("Unknown capability '%s'!", $capability)); @@ -557,7 +556,7 @@ case PhabricatorPolicyCapability::CAN_VIEW: if (!$this->canUninstall()) { return pht( - 'This application is required for Phabricator to operate, so all '. + 'This application is required, so all '. 'users must have access to it.'); } else { return null; diff -Nru phabricator-0~git20200925/phabricator/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php phabricator-0~git20220903/phabricator/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -27,11 +27,11 @@ $is_all = $args->getArg('all'); $key_list = $args->getArg('caches'); - if ($is_all && strlen($key_list)) { + if ($is_all && phutil_nonempty_string($key_list)) { throw new PhutilArgumentUsageException( pht( 'Specify either "--all" or "--caches", not both.')); - } else if (!$is_all && !strlen($key_list)) { + } else if (!$is_all && !phutil_nonempty_string($key_list)) { throw new PhutilArgumentUsageException( pht( 'Select caches to purge with "--all" or "--caches". Available '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/cache/spec/PhabricatorCacheSpec.php phabricator-0~git20220903/phabricator/src/applications/cache/spec/PhabricatorCacheSpec.php --- phabricator-0~git20200925/phabricator/src/applications/cache/spec/PhabricatorCacheSpec.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/cache/spec/PhabricatorCacheSpec.php 2022-06-14 16:29:55.000000000 +0000 @@ -96,8 +96,8 @@ $summary = pht('Enabling APC/APCu will improve performance.'); $message = pht( 'The APC or APCu PHP extensions are installed, but not enabled in your '. - 'PHP configuration. Enabling these extensions will improve Phabricator '. - 'performance. Edit the "%s" setting to enable these extensions.', + 'PHP configuration. Enabling these extensions will improve performance. '. + 'Edit the "%s" setting to enable these extensions.', 'apc.enabled'); return $this diff -Nru phabricator-0~git20200925/phabricator/src/applications/cache/spec/PhabricatorDataCacheSpec.php phabricator-0~git20220903/phabricator/src/applications/cache/spec/PhabricatorDataCacheSpec.php --- phabricator-0~git20200925/phabricator/src/applications/cache/spec/PhabricatorDataCacheSpec.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/cache/spec/PhabricatorDataCacheSpec.php 2022-06-14 16:29:55.000000000 +0000 @@ -70,7 +70,7 @@ if (version_compare(phpversion(), '5.5', '>=')) { $message = pht( 'Installing the "APCu" PHP extension will improve performance. '. - 'This extension is strongly recommended. Without it, Phabricator '. + 'This extension is strongly recommended. Without it, this software '. 'must rely on a very inefficient disk-based cache.'); $this diff -Nru phabricator-0~git20200925/phabricator/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php phabricator-0~git20220903/phabricator/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php --- phabricator-0~git20200925/phabricator/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php 2022-06-14 16:29:55.000000000 +0000 @@ -85,9 +85,9 @@ $message = pht( 'The "%s" setting is currently disabled in your PHP configuration, '. - 'but Phabricator is running in development mode. This option should '. - 'normally be enabled in development so you do not need to restart '. - 'anything after making changes to the code.', + 'but this software is running in development mode. This option '. + 'should normally be enabled in development so you do not need to '. + 'restart anything after making changes to the code.', 'apc.stat'); $this @@ -174,8 +174,7 @@ $message = pht( 'The PHP "Zend OPcache" extension is installed, but not enabled in '. 'your PHP configuration. Enabling it will dramatically improve '. - 'Phabricator performance. Edit the "%s" setting to '. - 'enable the extension.', + 'performance. Edit the "%s" setting to enable the extension.', 'opcache.enable'); $this->newIssue('extension.opcache.enable') diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php phabricator-0~git20220903/phabricator/src/applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/codex/PhabricatorCalendarEventPolicyCodex.php 2022-06-14 16:29:55.000000000 +0000 @@ -71,7 +71,7 @@ ->setIsActive($object->isImportedEvent()) ->setDescription( pht( - 'Imported events can not be edited in Phabricator.')); + 'Imported events can not be edited.')); return $rules; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/PhutilICSWriter.php phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/PhutilICSWriter.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/PhutilICSWriter.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/PhutilICSWriter.php 2022-06-14 16:29:55.000000000 +0000 @@ -128,11 +128,15 @@ $properties[] = $this->newTextProperty( 'PRODID', - '-//Phacility//Phabricator//EN'); + self::getICSPRODID()); return $properties; } + public static function getICSPRODID() { + return '-//Phacility//Phabricator//EN'; + } + private function getEventNodeProperties(PhutilCalendarEventNode $event) { $properties = array(); @@ -180,14 +184,14 @@ } $name = $event->getName(); - if (strlen($name)) { + if (phutil_nonempty_string($name)) { $properties[] = $this->newTextProperty( 'SUMMARY', $name); } $description = $event->getDescription(); - if (strlen($description)) { + if (phutil_nonempty_string($description)) { $properties[] = $this->newTextProperty( 'DESCRIPTION', $description); diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-christmas.ics phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-christmas.ics --- phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-christmas.ics 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-christmas.ics 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Phacility//Phabricator//EN +PRODID:${PRODID} BEGIN:VEVENT UID:christmas-day CREATED:20160901T232425Z diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-office-party.ics phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-office-party.ics --- phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-office-party.ics 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-office-party.ics 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Phacility//Phabricator//EN +PRODID:${PRODID} BEGIN:VEVENT UID:office-party CREATED:20161001T120000Z diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-recurring-christmas.ics phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-recurring-christmas.ics --- phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-recurring-christmas.ics 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-recurring-christmas.ics 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Phacility//Phabricator//EN +PRODID:${PRODID} BEGIN:VEVENT UID:recurring-christmas CREATED:20001225T000000Z diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-tea-time.ics phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-tea-time.ics --- phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-tea-time.ics 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/data/writer-tea-time.ics 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,6 @@ BEGIN:VCALENDAR VERSION:2.0 -PRODID:-//Phacility//Phabricator//EN +PRODID:${PRODID} BEGIN:VEVENT UID:tea-time CREATED:20160915T070000Z diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/PhutilICSWriterTestCase.php phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/PhutilICSWriterTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/parser/ics/__tests__/PhutilICSWriterTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/parser/ics/__tests__/PhutilICSWriterTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -138,6 +138,12 @@ private function assertICS($name, $actual) { $path = dirname(__FILE__).'/data/'.$name; $data = Filesystem::readFile($path); + + $data = str_replace( + '${PRODID}', + PhutilICSWriter::getICSPRODID(), + $data); + $this->assertEqual($data, $actual, pht('ICS: %s', $name)); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarExportQuery.php phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarExportQuery.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarExportQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarExportQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorCalendarExport(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarExternalInviteeQuery.php phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarExternalInviteeQuery.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarExternalInviteeQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarExternalInviteeQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorCalendarExternalInvitee(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarImportLogQuery.php phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarImportLogQuery.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarImportLogQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarImportLogQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorCalendarImportLog(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarImportQuery.php phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarImportQuery.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/query/PhabricatorCalendarImportQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/query/PhabricatorCalendarImportQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhabricatorCalendarImport(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/calendar/storage/PhabricatorCalendarEvent.php phabricator-0~git20220903/phabricator/src/applications/calendar/storage/PhabricatorCalendarEvent.php --- phabricator-0~git20200925/phabricator/src/applications/calendar/storage/PhabricatorCalendarEvent.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/calendar/storage/PhabricatorCalendarEvent.php 2022-06-14 16:29:55.000000000 +0000 @@ -24,7 +24,6 @@ protected $isCancelled; protected $isAllDay; protected $icon; - protected $mailKey; protected $isStub; protected $isRecurring = 0; @@ -360,10 +359,6 @@ } public function save() { - if (!$this->mailKey) { - $this->mailKey = Filesystem::readRandomCharacters(20); - } - $import_uid = $this->getImportUID(); if ($import_uid !== null) { $index = PhabricatorHash::digestForIndex($import_uid); @@ -405,7 +400,6 @@ 'isCancelled' => 'bool', 'isAllDay' => 'bool', 'icon' => 'text32', - 'mailKey' => 'bytes20', 'isRecurring' => 'bool', 'seriesParentPHID' => 'phid?', 'instanceOfEventPHID' => 'phid?', @@ -442,9 +436,8 @@ ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - PhabricatorCalendarEventPHIDType::TYPECONST); + public function getPHIDType() { + return PhabricatorCalendarEventPHIDType::TYPECONST; } public function getMonogram() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitAPIController.php phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitAPIController.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitAPIController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitAPIController.php 2022-06-14 16:29:55.000000000 +0000 @@ -238,6 +238,16 @@ if ($object instanceof PhabricatorUser) { $user = $object; } else { + if ($object->isDisabled()) { + return array( + 'ERR-INVALID-AUTH', + pht( + 'The key which signed this request is associated with a '. + 'disabled device ("%s").', + $object->getName()), + ); + } + if (!$stored_key->getIsTrusted()) { return array( 'ERR-INVALID-AUTH', @@ -251,9 +261,9 @@ return array( 'ERR-INVALID-AUTH', pht( - 'This request originates from outside of the Phabricator '. - 'cluster address range. Requests signed with trusted '. - 'device keys must originate from within the cluster.'), + 'This request originates from outside of the cluster address '. + 'range. Requests signed with trusted device keys must '. + 'originate from within the cluster.'), ); } @@ -354,9 +364,9 @@ return array( 'ERR-INVALID-AUTH', pht( - 'This request originates from outside of the Phabricator '. - 'cluster address range. Requests signed with cluster API '. - 'tokens must originate from within the cluster.'), + 'This request originates from outside of the cluster address '. + 'range. Requests signed with cluster API tokens must '. + 'originate from within the cluster.'), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitConsoleController.php phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitConsoleController.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitConsoleController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitConsoleController.php 2022-06-14 16:29:55.000000000 +0000 @@ -88,23 +88,118 @@ $crumbs->addTextCrumb($method->getAPIMethodName()); $crumbs->setBorder(true); + $documentation_pages = $method->getDocumentationPages($viewer); + + $documentation_view = $this->newDocumentationView( + $method, + $documentation_pages); + $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setFooter(array( + + id(new PhabricatorAnchorView()) + ->setAnchorName('overview'), $info_box, - $method->getMethodDocumentation(), + + id(new PhabricatorAnchorView()) + ->setAnchorName('documentation'), + $documentation_view, + + id(new PhabricatorAnchorView()) + ->setAnchorName('call'), $form_box, + + id(new PhabricatorAnchorView()) + ->setAnchorName('examples'), $this->renderExampleBox($method, null), )); $title = $method->getAPIMethodName(); + $nav = $this->newNavigationView($method, $documentation_pages); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($nav) ->appendChild($view); } + private function newDocumentationView( + ConduitAPIMethod $method, + array $documentation_pages) { + assert_instances_of($documentation_pages, 'ConduitAPIDocumentationPage'); + + $viewer = $this->getViewer(); + + $description_properties = id(new PHUIPropertyListView()); + + $description_properties->addTextContent( + new PHUIRemarkupView($viewer, $method->getMethodDescription())); + + $description_box = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Method Description')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->appendChild($description_properties); + + $view = array(); + $view[] = $description_box; + + foreach ($documentation_pages as $page) { + $view[] = $page->newView(); + } + + return $view; + } + + private function newNavigationView( + ConduitAPIMethod $method, + array $documentation_pages) { + assert_instances_of($documentation_pages, 'ConduitAPIDocumentationPage'); + + $console_uri = urisprintf( + '/method/%s/', + $method->getAPIMethodName()); + $console_uri = $this->getApplicationURI($console_uri); + $console_uri = new PhutilURI($console_uri); + + $nav = id(new AphrontSideNavFilterView()) + ->setBaseURI($console_uri); + + $nav->selectFilter(null); + + $nav->newLink('overview') + ->setHref('#overview') + ->setName(pht('Overview')) + ->setIcon('fa-list'); + + $nav->newLink('documentation') + ->setHref('#documentation') + ->setName(pht('Documentation')) + ->setIcon('fa-book'); + + foreach ($documentation_pages as $page) { + $nav->newLink($page->getAnchor()) + ->setHref('#'.$page->getAnchor()) + ->setName($page->getName()) + ->setIcon($page->getIconIcon()) + ->setIndented(true); + } + + $nav->newLink('call') + ->setHref('#call') + ->setName(pht('Call Method')) + ->setIcon('fa-play'); + + $nav->newLink('examples') + ->setHref('#examples') + ->setName(pht('Examples')) + ->setIcon('fa-folder-open-o'); + + return $nav; + } + private function buildMethodProperties(ConduitAPIMethod $method) { $viewer = $this->getViewer(); @@ -171,7 +266,6 @@ pht('Errors'), $error_description); - $scope = $method->getRequiredScope(); switch ($scope) { case ConduitAPIMethod::SCOPE_ALWAYS: @@ -201,11 +295,6 @@ $oauth_description, )); - $view->addSectionHeader( - pht('Description'), PHUIPropertyListView::ICON_SUMMARY); - $view->addTextContent( - new PHUIRemarkupView($viewer, $method->getMethodDescription())); - return $view; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitController.php phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitController.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitController.php 2022-06-14 16:29:55.000000000 +0000 @@ -142,6 +142,8 @@ $parts[] = '--conduit-token '; $parts[] = phutil_tag('strong', array(), '<conduit-token>'); $parts[] = ' '; + $parts[] = '--'; + $parts[] = ' '; $parts[] = $method->getAPIMethodName(); @@ -154,7 +156,7 @@ $parts = array(); - $libphutil_path = 'path/to/libphutil/src/__phutil_library_init__.php'; + $libphutil_path = 'path/to/arcanist/support/init/init-script.php'; $parts[] = '<?php'; $parts[] = "\n\n"; diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitTokenEditController.php phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitTokenEditController.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/controller/PhabricatorConduitTokenEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/controller/PhabricatorConduitTokenEditController.php 2022-06-14 16:29:55.000000000 +0000 @@ -87,9 +87,9 @@ if ($token->getTokenType() === PhabricatorConduitToken::TYPE_CLUSTER) { $dialog->appendChild( pht( - 'This token is automatically generated by Phabricator, and used '. - 'to make requests between nodes in a Phabricator cluster. You '. - 'can not use this token in external applications.')); + 'This token is automatically generated, and used to make '. + 'requests between nodes in a cluster. You can not use this '. + 'token in external applications.')); } else { $form->appendChild( id(new AphrontFormTextControl()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/data/ConduitAPIDocumentationPage.php phabricator-0~git20220903/phabricator/src/applications/conduit/data/ConduitAPIDocumentationPage.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/data/ConduitAPIDocumentationPage.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/data/ConduitAPIDocumentationPage.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,61 @@ +<?php + +final class ConduitAPIDocumentationPage + extends Phobject { + + private $name; + private $anchor; + private $iconIcon; + private $content = array(); + + public function setName($name) { + $this->name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + + public function setAnchor($anchor) { + $this->anchor = $anchor; + return $this; + } + + public function getAnchor() { + return $this->anchor; + } + + public function setContent($content) { + $this->content = $content; + return $this; + } + + public function getContent() { + return $this->content; + } + + public function setIconIcon($icon_icon) { + $this->iconIcon = $icon_icon; + return $this; + } + + public function getIconIcon() { + return $this->iconIcon; + } + + public function newView() { + $anchor_name = $this->getAnchor(); + $anchor_view = id(new PhabricatorAnchorView()) + ->setAnchorName($anchor_name); + + $content = $this->content; + + return array( + $anchor_view, + $content, + ); + } + + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/method/ConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/conduit/method/ConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/method/ConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/method/ConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,8 +40,33 @@ */ abstract public function getMethodDescription(); - public function getMethodDocumentation() { - return null; + final public function getDocumentationPages(PhabricatorUser $viewer) { + $pages = $this->newDocumentationPages($viewer); + return $pages; + } + + protected function newDocumentationPages(PhabricatorUser $viewer) { + return array(); + } + + final protected function newDocumentationPage(PhabricatorUser $viewer) { + return id(new ConduitAPIDocumentationPage()) + ->setIconIcon('fa-chevron-right'); + } + + final protected function newDocumentationBoxPage( + PhabricatorUser $viewer, + $title, + $content) { + + $box_view = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setTable($content); + + return $this->newDocumentationPage($viewer) + ->setName($title) + ->setContent($box_view); } abstract protected function defineParamTypes(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/method/ConduitConnectConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -80,7 +80,7 @@ $ex->setErrorDescription( pht( "Your '%s' client version is '%d', which is newer than the ". - "server version, '%d'. Upgrade your Phabricator install.", + "server version, '%d'. Upgrade your server.", 'arc', $client_version, $server_version)); diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/query/PhabricatorConduitLogQuery.php phabricator-0~git20220903/phabricator/src/applications/conduit/query/PhabricatorConduitLogQuery.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/query/PhabricatorConduitLogQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/query/PhabricatorConduitLogQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,10 +40,6 @@ return new PhabricatorConduitMethodCallLog(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/query/PhabricatorConduitSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/conduit/query/PhabricatorConduitSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/query/PhabricatorConduitSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/query/PhabricatorConduitSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -88,7 +88,7 @@ pht('Deprecated Methods'), pht( 'Show old methods which will be deleted in a future '. - 'version of Phabricator.')), + 'version of this software.')), $is_deprecated)); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/conduit/query/PhabricatorConduitTokenQuery.php phabricator-0~git20220903/phabricator/src/applications/conduit/query/PhabricatorConduitTokenQuery.php --- phabricator-0~git20200925/phabricator/src/applications/conduit/query/PhabricatorConduitTokenQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/conduit/query/PhabricatorConduitTokenQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorConduitToken(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/application/PhabricatorConfigApplication.php phabricator-0~git20220903/phabricator/src/applications/config/application/PhabricatorConfigApplication.php --- phabricator-0~git20200925/phabricator/src/applications/config/application/PhabricatorConfigApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/application/PhabricatorConfigApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -31,7 +31,7 @@ } public function getShortDescription() { - return pht('Configure Phabricator'); + return pht('Configure %s', PlatformSymbols::getPlatformServerName()); } public function getRoutes() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorBaseURISetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorBaseURISetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorBaseURISetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorBaseURISetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -17,7 +17,7 @@ $message = pht( 'This request did not include a "Host" header. This may mean that '. 'your webserver (like nginx or apache) is misconfigured so the '. - '"Host" header is not making it to Phabricator, or that you are '. + '"Host" header is not making it to this software, or that you are '. 'making a raw request without a "Host" header using a tool or '. 'library.'. "\n\n". @@ -38,9 +38,9 @@ 'is required for some browsers to be able to set cookies.'. "\n\n". 'This may mean the base URI is configured incorrectly. You must '. - 'serve Phabricator from a base URI with a dot (like '. - '"https://phabricator.mycompany.com"), not a bare domain '. - '(like "https://phabricator/"). If you are trying to use a bare '. + 'serve this software from a base URI with a dot (like '. + '"https://devtools.example.com"), not a bare domain '. + '(like "https://devtools/"). If you are trying to use a bare '. 'domain, change your configuration to use a full domain with a dot '. 'in it instead.'. "\n\n". @@ -76,7 +76,7 @@ 'will not work properly until you configure it.'. "\n\n". 'You should set the base URI to the URI you will use to access '. - 'Phabricator, like "http://phabricator.example.com/".'. + 'this server, like "http://devtools.example.com/".'. "\n\n". 'Include the protocol (http or https), domain name, and port number if '. 'you are using a port other than 80 (http) or 443 (https).'. @@ -96,7 +96,7 @@ ->setMessage($message) ->addCommand( hsprintf( - '<tt>phabricator/ $</tt> %s', + '<tt>$</tt> %s', csprintf( './bin/config set phabricator.base-uri %s', $base_uri_guess))); diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorBinariesSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorBinariesSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorBinariesSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorBinariesSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,7 +15,7 @@ if (!Filesystem::binaryExists($bin_name)) { $message = pht( - "Without '%s', Phabricator can not test for the availability ". + "Without '%s', this software can not test for the availability ". "of other binaries.", $bin_name); $this->raiseWarning($bin_name, $message); @@ -27,7 +27,7 @@ if (!Filesystem::binaryExists('diff')) { $message = pht( - "Without '%s', Phabricator will not be able to generate or render ". + "Without '%s', this software will not be able to generate or render ". "diffs in multiple applications.", 'diff'); $this->raiseWarning('diff', $message); @@ -120,17 +120,11 @@ break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $bad_versions = array( - // We need 1.9 for HTTP cloning, see T3046. - '< 1.9' => pht( - 'The minimum supported version of Mercurial is 1.9, which was '. - 'released in 2011.'), - '= 2.1' => pht( - 'This version of Mercurial returns a bad exit code '. - 'after a successful pull.'), - '= 2.2' => pht( - 'This version of Mercurial has a significant memory leak, fixed '. - 'in 2.2.1. Pushing fails with this version as well; see %s.', - 'T3046#54922'), + // We need 2.4 for utilizing `{p1node}` keyword in templates, see + // D21679 and D21681. + '< 2.4' => pht( + 'The minimum supported version of Mercurial is 2.4, which was '. + 'released in 2012.'), ); break; } @@ -168,7 +162,7 @@ $preamble = pht( "The '%s' binary could not be found. Set the webserver's %s ". "environmental variable to include the directory where it resides, or ". - "add that directory to '%s' in the Phabricator configuration.", + "add that directory to '%s' in configuration.", $bin, 'PATH', 'environment.append-paths'); @@ -176,10 +170,9 @@ $preamble = pht( "The '%s' binary could not be found. Symlink it into '%s', or set the ". "webserver's %s environmental variable to include the directory where ". - "it resides, or add that directory to '%s' in the Phabricator ". - "configuration.", + "it resides, or add that directory to '%s' in configuration.", $bin, - 'phabricator/support/bin/', + 'support/bin/', 'PATH', 'environment.append-paths'); } @@ -200,19 +193,19 @@ $message = pht( 'Unable to determine the version number of "%s". Usually, this means '. - 'the program changed its version format string recently and Phabricator '. - 'does not know how to parse the new one yet, but might indicate that '. - 'you have a very old (or broken) binary.'. + 'the program changed its version format string recently and this '. + 'software does not know how to parse the new one yet, but might '. + 'indicate that you have a very old (or broken) binary.'. "\n\n". 'Because we can not determine the version number, checks against '. 'minimum and known-bad versions will be skipped, so we might fail '. 'to detect an incompatible binary.'. "\n\n". - 'You may be able to resolve this issue by updating Phabricator, since '. - 'a newer version of Phabricator is likely to be able to parse the '. + 'You may be able to resolve this issue by updating this server, since '. + 'a newer version of the software is likely to be able to parse the '. 'newer version string.'. "\n\n". - 'If updating Phabricator does not fix this, you can report the issue '. + 'If updating the software does not fix this, you can report the issue '. 'to the upstream so we can adjust the parser.'. "\n\n". 'If you are confident you have a recent version of "%s" installed and '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorDaemonsSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorDaemonsSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorDaemonsSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorDaemonsSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,14 +26,13 @@ $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd'); $summary = pht( - 'You must start the Phabricator daemons to send email, rebuild '. - 'search indexes, and do other background processing.'); + 'You must start the daemons to send email, rebuild search indexes, '. + 'and do other background processing.'); $message = pht( - 'The Phabricator daemons are not running, so Phabricator will not '. - 'be able to perform background processing (including sending email, '. - 'rebuilding search indexes, importing commits, cleaning up old data, '. - 'and running builds).'. + 'The daemons are not running, background processing (including '. + 'sending email, rebuilding search indexes, importing commits, '. + 'cleaning up old data, and running builds) can not be performed.'. "\n\n". 'Use %s to start daemons. See %s for more information.', phutil_tag('tt', array(), 'bin/phd start'), @@ -47,10 +46,10 @@ $this->newIssue('daemons.not-running') ->setShortName(pht('Daemons Not Running')) - ->setName(pht('Phabricator Daemons Are Not Running')) + ->setName(pht('Daemons Are Not Running')) ->setSummary($summary) ->setMessage($message) - ->addCommand('phabricator/ $ ./bin/phd start'); + ->addCommand('$ ./bin/phd start'); } $expect_user = PhabricatorEnv::getEnvConfig('phd.user'); @@ -91,7 +90,7 @@ ->setSummary($summary) ->setMessage($message) ->addPhabricatorConfig('phd.user') - ->addCommand('phabricator/ $ ./bin/phd restart'); + ->addCommand('$ ./bin/phd restart'); break; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorDatabaseSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorDatabaseSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorDatabaseSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorDatabaseSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,11 +35,11 @@ ->addPhabricatorConfig('mysql.port') ->addCommand( hsprintf( - '<tt>phabricator/ $</tt> ./bin/config set mysql.host %s', + '<tt>$</tt> ./bin/config set mysql.host %s', $host)) ->addCommand( hsprintf( - '<tt>phabricator/ $</tt> ./bin/config set mysql.port %s', + '<tt>$</tt> ./bin/config set mysql.port %s', $port)); } @@ -134,7 +134,7 @@ ->setName(pht('Setup MySQL Schema')) ->setMessage($message) ->setIsFatal(true) - ->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade')); + ->addCommand(hsprintf('<tt>$</tt> ./bin/storage upgrade')); return true; } @@ -160,7 +160,7 @@ ->setIsFatal(true) ->setMessage($message) ->addCommand( - hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade')); + hsprintf('<tt>$</tt> ./bin/storage upgrade')); return true; } @@ -177,7 +177,7 @@ 'Database host "%s" is configured as a master, but is replicating '. 'another host. This is dangerous and can mangle or destroy data. '. 'Only replicas should be replicating. Stop replication on the '. - 'host or reconfigure Phabricator.', + 'host or adjust configuration.', $ref->getRefKey()); $this->newIssue('db.master.replicating') diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorElasticsearchSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorElasticsearchSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorElasticsearchSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorElasticsearchSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,8 +34,8 @@ } catch (Exception $ex) { $summary = pht('Elasticsearch is not reachable as configured.'); $message = pht( - 'Elasticsearch is configured (with the %s setting) but Phabricator'. - ' encountered an exception when trying to test the index.'. + 'Elasticsearch is configured (with the %s setting) but an '. + 'exception was encountered when trying to test the index.'. "\n\n". '%s', phutil_tag('tt', array(), 'cluster.search'), @@ -69,7 +69,7 @@ 'Elasticsearch index exists but needs correction.'); $message = pht( - 'Either the Phabricator schema for Elasticsearch has changed '. + 'Either the schema for Elasticsearch has changed '. 'or Elasticsearch created the index automatically. '. 'Use the following command to rebuild the index.'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,9 +38,9 @@ } else { $summary = pht('This option is not recognized. It may be misspelled.'); $message = pht( - "The configuration option '%s' is not recognized. It may be ". - "misspelled, or it might have existed in an older version of ". - "Phabricator. It has no effect, and should be corrected or deleted.", + 'The configuration option "%s" is not recognized. It may be '. + 'misspelled, or it might have existed in an older version of '. + 'the software. It has no effect, and should be corrected or deleted.', $key); $short = pht('Unknown Config'); $name = pht('Unknown Configuration Option "%s"', $key); @@ -76,7 +76,7 @@ $issue->setMessage($message); if ($found_local) { - $command = csprintf('phabricator/ $ ./bin/config delete %s', $key); + $command = csprintf('$ ./bin/config delete %s', $key); $issue->addCommand($command); } @@ -155,7 +155,7 @@ 'details about this setup issue, see %s.'. "\n\n". 'This database value is currently respected, but a future version '. - 'of Phabricator will stop respecting database values for locked '. + 'of the software will stop respecting database values for locked '. 'configuration options.', $key, $set_command, @@ -167,7 +167,7 @@ ), $doc_name)); $command = csprintf( - 'phabricator/ $ ./bin/config delete --database %R', + '$ ./bin/config delete --database %R', $key); $this->newIssue('config.locked.'.$key) @@ -191,7 +191,7 @@ pht( 'The "feed.http-hooks" option is deprecated in favor of '. 'Webhooks. This option will be removed in a future version '. - 'of Phabricator.'. + 'of the software.'. "\n\n". 'You can configure Webhooks in Herald.'. "\n\n". @@ -283,8 +283,7 @@ 'Reply handlers can no longer be overridden with configuration.'); $monospace_reason = pht( - 'Phabricator no longer supports global customization of monospaced '. - 'fonts.'); + 'Global customization of monospaced fonts is no longer supported.'); $public_mail_reason = pht( 'Inbound mail addresses are now configured for each application '. @@ -346,7 +345,7 @@ 'auth.sshkeys.enabled' => pht( 'SSH keys are now actually useful, so they are always enabled.'), 'differential.anonymous-access' => pht( - 'Phabricator now has meaningful global access controls. See `%s`.', + 'Global access controls now exist, see `%s`.', 'policy.allow-public'), 'celerity.resource-path' => pht( 'An alternate resource map is no longer supported. Instead, use '. @@ -356,7 +355,7 @@ 'auth.sessions.conduit' => $session_reason, 'auth.sessions.web' => $session_reason, 'tokenizer.ondemand' => pht( - 'Phabricator now manages typeahead strategies automatically.'), + 'Typeahead strategies are now managed automatically.'), 'differential.revision-custom-detail-renderer' => pht( 'Obsolete; use standard rendering events instead.'), 'differential.show-host-field' => $differential_field_reason, @@ -383,16 +382,15 @@ 'pool size with `%s`.', 'phd.taskmasters'), 'storage.engine-selector' => pht( - 'Phabricator now automatically discovers available storage engines '. - 'at runtime.'), + 'Storage engines are now discovered automatically at runtime.'), 'storage.upload-size-limit' => pht( - 'Phabricator now supports arbitrarily large files. Consult the '. + 'Arbitrarily large files are now supported. Consult the '. 'documentation for configuration details.'), 'security.allow-outbound-http' => pht( 'This option has been replaced with the more granular option `%s`.', 'security.outbound-blacklist'), 'metamta.reply.show-hints' => pht( - 'Phabricator no longer shows reply hints in mail.'), + 'Reply hints are no longer shown in mail.'), 'metamta.differential.reply-handler-domain' => $reply_domain_reason, 'metamta.diffusion.reply-handler-domain' => $reply_domain_reason, @@ -406,15 +404,15 @@ 'metamta.package.reply-handler' => $reply_handler_reason, 'metamta.precedence-bulk' => pht( - 'Phabricator now always sends transaction mail with '. - '"Precedence: bulk" to improve deliverability.'), + 'Transaction mail is now always sent with "Precedence: bulk" to '. + 'improve deliverability.'), 'style.monospace' => $monospace_reason, 'style.monospace.windows' => $monospace_reason, 'search.engine-selector' => pht( - 'Phabricator now automatically discovers available search engines '. - 'at runtime.'), + 'Available search engines are now automatically discovered at '. + 'runtime.'), 'metamta.files.public-create-email' => $public_mail_reason, 'metamta.maniphest.public-create-email' => $public_mail_reason, @@ -469,12 +467,12 @@ 'maniphest.priorities.needs-triage' => $dashboard_reason, 'mysql.implementation' => pht( - 'Phabricator now automatically selects the best available '. - 'MySQL implementation.'), + 'The best available MYSQL implementation is now selected '. + 'automatically.'), 'mysql.configuration-provider' => pht( - 'Phabricator now has application-level management of partitioning '. - 'and replicas.'), + 'Partitioning and replication are now managed in primary '. + 'configuration.'), 'search.elastic.host' => $elastic_reason, 'search.elastic.namespace' => $elastic_reason, @@ -541,7 +539,7 @@ 'Whitespace rendering is now handled automatically.'), 'phd.pid-directory' => pht( - 'Phabricator daemons no longer use PID files.'), + 'Daemons no longer use PID files.'), 'phd.trace' => $phd_reason, 'phd.verbose' => $phd_reason, diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorFileinfoSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorFileinfoSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorFileinfoSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorFileinfoSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,7 +10,7 @@ if (!extension_loaded('fileinfo')) { $message = pht( "The '%s' extension is not installed. Without '%s', ". - "support, Phabricator may not be able to determine the MIME types ". + "support, this software may not be able to determine the MIME types ". "of uploaded files.", 'fileinfo', 'fileinfo'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorGDSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorGDSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorGDSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorGDSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,7 +10,7 @@ if (!extension_loaded('gd')) { $message = pht( "The '%s' extension is not installed. Without '%s', support, ". - "Phabricator will not be able to process or resize images ". + "this server will not be able to process or resize images ". "(for example, to generate thumbnails). Install or enable '%s'.", 'gd', 'gd', @@ -41,7 +41,7 @@ $message = pht( "The '%s' extension has support for only some image types. ". - "Phabricator will be unable to process images of the missing ". + "This server will be unable to process images of the missing ". "types until you build '%s' with support for them. ". "Supported types: %s. Missing types: %s.", 'gd', diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorMailSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorMailSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorMailSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorMailSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -12,9 +12,9 @@ } $message = pht( - 'You haven\'t configured mailers yet, so Phabricator won\'t be able '. + 'You haven\'t configured mailers yet, so this server won\'t be able '. 'to send outbound mail or receive inbound mail. See the '. - 'configuration setting cluster.mailers for details.'); + 'configuration setting "cluster.mailers" for details.'); $this->newIssue('cluster.mailers') ->setName(pht('Mailers Not Configured')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorManualActivitySetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorManualActivitySetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorManualActivitySetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorManualActivitySetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,7 +42,7 @@ 'function correctly.'); $message[] = pht( - 'You can rebuild the search index while Phabricator is running.'); + 'You can rebuild the search index while the server is running.'); $message[] = pht( 'To rebuild the index, run this command:'); @@ -51,7 +51,7 @@ 'pre', array(), (string)csprintf( - 'phabricator/ $ ./bin/search index --all --force --background')); + '$ ./bin/search index --all --force --background')); $message[] = pht( 'You can find more information about rebuilding the search '. @@ -71,7 +71,7 @@ $message[] = phutil_tag( 'pre', array(), - 'phabricator/ $ ./bin/config done reindex'); + '$ ./bin/config done reindex'); $activity_message = phutil_implode_html("\n\n", $message); @@ -84,27 +84,34 @@ private function raiseRebuildIdentitiesIssue() { $activity_name = pht('Rebuild Repository Identities'); $activity_summary = pht( - 'The mapping from VCS users to Phabricator users has changed '. - 'and must be rebuilt.'); + 'The mapping from VCS users to %s users has changed '. + 'and must be rebuilt.', + PlatformSymbols::getPlatformServerName()); $message = array(); $message[] = pht( - 'The way Phabricator attributes VCS activity to Phabricator users '. - 'has changed. There is a new indirection layer between the strings '. - 'that appear as VCS authors and committers (such as "John Developer '. - '<johnd@bigcorp.com>") and the Phabricator user that gets associated '. - 'with VCS commits. This is to support situations where users '. - 'are incorrectly associated with commits by Phabricator making bad '. - 'guesses about the identity of the corresponding Phabricator user. '. + 'The way VCS activity is attributed %s user accounts has changed.', + PlatformSymbols::getPlatformServerName()); + + $message[] = pht( + 'There is a new indirection layer between the strings that appear as '. + 'VCS authors and committers (such as "John Developer '. + '<johnd@bigcorp.com>") and the user account that gets associated '. + 'with VCS commits.'); + + $message[] = pht( + 'This change supports situations where users are incorrectly '. + 'associated with commits because the software makes a bad guess '. + 'about how the VCS string maps to a user account. '. 'This also helps with situations where existing repositories are '. 'imported without having created accounts for all the committers to '. 'that repository. Until you rebuild these repository identities, you '. - 'are likely to encounter problems with future Phabricator features '. - 'which will rely on the existence of these identities.'); + 'are likely to encounter problems with features which rely on the '. + 'existence of these identities.'); $message[] = pht( - 'You can rebuild repository identities while Phabricator is running.'); + 'You can rebuild repository identities while the server is running.'); $message[] = pht( 'To rebuild identities, run this command:'); @@ -113,8 +120,7 @@ 'pre', array(), (string)csprintf( - 'phabricator/ $ '. - './bin/repository rebuild-identities --all-repositories')); + '$ ./bin/repository rebuild-identities --all-repositories')); $message[] = pht( 'You can find more information about this new identity mapping '. @@ -134,7 +140,7 @@ $message[] = phutil_tag( 'pre', array(), - 'phabricator/ $ ./bin/config done identities'); + '$ ./bin/config done identities'); $activity_message = phutil_implode_html("\n\n", $message); diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorMySQLSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorMySQLSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorMySQLSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorMySQLSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -66,7 +66,7 @@ 'fit into the column), or security concerns (for example, by '. 'truncating keys or credentials).'. "\n\n". - 'Phabricator is developed and tested in "STRICT_ALL_TABLES" mode so '. + 'This software is developed and tested in "STRICT_ALL_TABLES" mode so '. 'you should normally never encounter these situations, but may run '. 'into them if you interact with the database directly, run '. 'third-party code, develop extensions, or just encounter a bug in '. @@ -88,7 +88,7 @@ 'they may not work in strict mode.'. "\n\n". 'If you can not or do not want to enable "STRICT_ALL_TABLES", you '. - 'can safely ignore this warning. Phabricator will work correctly '. + 'can safely ignore this warning. This software will work correctly '. 'with this mode enabled or disabled.', $host_name, phutil_tag('pre', array(), 'sql_mode=STRICT_ALL_TABLES')); @@ -151,7 +151,7 @@ $message = pht( "Database host \"%s\" is using the builtin stopword file for ". - "building search indexes. This can make Phabricator's search ". + "building search indexes. This can make the search ". "feature less useful.\n\n". "Stopwords are common words which are not indexed and thus can not ". "be searched for. The default stopword file has about 500 words, ". @@ -273,11 +273,11 @@ "There are no hard-and-fast rules to setting an appropriate value, ". "but a reasonable starting point for a standard install is something ". "like 40%% of the total memory on the machine. For example, if you ". - "have 4GB of RAM on the machine you have installed Phabricator on, ". + "have 4GB of RAM on the machine you have installed this software on, ". "you might set this value to %s.\n\n". "You can read more about this option in the MySQL documentation to ". "help you make a decision about how to configure it for your use ". - "case. There are no concerns specific to Phabricator which make it ". + "case. There are no concerns specific to this software which make it ". "different from normal workloads with respect to this setting.\n\n". "To adjust the setting, add something like this to your %s file (in ". "the %s section), replacing %s with an appropriate value for your ". diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPathSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPathSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPathSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPathSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,15 +13,15 @@ if (!$path) { $summary = pht( - 'The environmental variable %s is empty. Phabricator will not '. + 'The environmental variable %s is empty. This server will not '. 'be able to execute some commands.', '$PATH'); $message = pht( - "The environmental variable %s is empty. Phabricator needs to execute ". + "The environmental variable %s is empty. This server needs to execute ". "some system commands, like `%s`, `%s`, `%s`, and `%s`. To execute ". "these commands, the binaries must be available in the webserver's ". - "%s. You can set additional paths in Phabricator configuration.", + "%s. You can set additional paths in configuration.", '$PATH', 'svn', 'git', @@ -120,7 +120,7 @@ ->setMessage( pht( "The configured PATH includes a component which is not usable. ". - "Phabricator will be unable to find or execute binaries located ". + "This server will be unable to find or execute binaries located ". "here:". "\n\n". "%s". diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,8 +21,8 @@ 'REMOTE_ADDR is no longer empty.'); $message = pht( - 'No REMOTE_ADDR is available, so Phabricator cannot determine the '. - 'origin address for requests. This will prevent Phabricator from '. + 'No REMOTE_ADDR is available, so this server cannot determine the '. + 'origin address for requests. This will prevent the software from '. 'performing important security checks. This most often means you '. 'have a mistake in your preamble script. Consult the documentation '. '(%s) and double-check that the script is written correctly.', @@ -76,8 +76,8 @@ 'with the database. You should install the newer "mysqli" extension '. 'to improve behaviors (like error handling and query timeouts).'. "\n\n". - 'Phabricator will work with the older extension, but upgrading to the '. - 'newer extension is recommended.'. + 'This software will work with the older extension, but upgrading to '. + 'the newer extension is recommended.'. "\n\n". 'You may be able to install the extension with a command like: %s', @@ -96,10 +96,10 @@ $message = pht( 'PHP is currently using the older MySQL external driver instead of '. 'the newer MySQL native driver. The older driver lacks options and '. - 'features (like support for query timeouts) which allow Phabricator '. + 'features (like support for query timeouts) which allow this server '. 'to interact better with the database.'. "\n\n". - 'Phabricator will work with the older driver, but upgrading to the '. + 'This software will work with the older driver, but upgrading to the '. 'native driver is recommended.'. "\n\n". 'You may be able to install the native driver with a command like: %s', @@ -134,7 +134,7 @@ 'and the client will comply.'. "\n\n". 'Although it is normally difficult for an attacker to convince '. - 'Phabricator to connect to a malicious MySQL server, you should '. + 'this software to connect to a malicious MySQL server, you should '. 'disable this option: this capability is unnecessary and inherently '. 'dangerous.'. "\n\n". diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPHPPreflightSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,11 +15,11 @@ if (version_compare($version, 7, '>=') && version_compare($version, 7.1, '<')) { $message = pht( - 'You are running PHP version %s. Phabricator does not support PHP '. - 'versions between 7.0 and 7.1.'. + 'You are running PHP version %s. PHP versions between 7.0 and 7.1 '. + 'are not supported'. "\n\n". - 'PHP removed signal handling features that Phabricator requires in '. - 'PHP 7.0, and did not restore them until PHP 7.1.'. + 'PHP removed reqiured signal handling features in '. + 'PHP 7.0, and did not restore an equivalent mechanism until PHP 7.1.'. "\n\n". 'Upgrade to PHP 7.1 or newer (recommended) or downgrade to an older '. 'version of PHP 5 (discouraged).', @@ -31,15 +31,18 @@ ->setMessage($message) ->addLink( 'https://phurl.io/u/php7', - pht('Phabricator PHP 7 Compatibility Information')); + pht('PHP 7 Compatibility Information')); return; } + // TODO: This can be removed entirely because the minimum PHP version is + // now PHP 5.5, which does not have safe mode. + $safe_mode = ini_get('safe_mode'); if ($safe_mode) { $message = pht( - "You have '%s' enabled in your PHP configuration, but Phabricator ". + "You have '%s' enabled in your PHP configuration, but this software ". "will not run in safe mode. Safe mode has been deprecated in PHP 5.3 ". "and removed in PHP 5.4.\n\nDisable safe mode to continue.", 'safe_mode'); @@ -89,7 +92,7 @@ if ($fatal) { $message = pht( "You have '%s' enabled in your PHP configuration.\n\n". - "This option is not compatible with Phabricator. Remove ". + "This option is not compatible with this software. Remove ". "'%s' from your configuration to continue.", $disable_option, $disable_option); @@ -108,7 +111,7 @@ if ($func_overload) { $message = pht( "You have '%s' enabled in your PHP configuration.\n\n". - "This option is not compatible with Phabricator. Disable ". + "This option is not compatible with this software. Disable ". "'%s' in your PHP configuration to continue.", $overload_option, $overload_option); @@ -131,7 +134,7 @@ // rare (particularly in supported environments). $message = pht( - "Your server is configured with '%s', which prevents Phabricator ". + "Your server is configured with '%s', which prevents this software ". "from opening files it requires access to.\n\n". "Disable this setting to continue.", 'open_basedir'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPygmentSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPygmentSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorPygmentSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorPygmentSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,7 +42,7 @@ 'pygmentize'); $message = pht( - 'Phabricator has %s available in %s, but the binary '. + 'This server has %s available in %s, but the binary '. 'exited with an error code when run as %s. Check that it is '. 'installed correctly.', phutil_tag('tt', array(), 'pygmentize'), @@ -64,7 +64,7 @@ 'to provide advanced syntax highlighting.'); $message = pht( - 'Phabricator can highlight a few languages by default, '. + 'This software can highlight a few languages by default, '. 'but installing and enabling Pygments (a third-party highlighting '. "tool) will add syntax highlighting for many more languages. \n\n". 'For instructions on installing and enabling Pygments, see the '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorRepositoriesSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -45,9 +45,9 @@ 'readable by the webserver.'); $message = pht( "The directory for local repositories (%s) does not exist, or is not ". - "readable by the webserver. Phabricator uses this directory to store ". - "information about repositories. If this directory does not exist, ". - "create it:\n\n". + "readable by the webserver. This software uses this directory to ". + "store information about repositories. If this directory does not ". + "exist, create it:\n\n". "%s\n". "If this directory exists, make it readable to the webserver. You ". "can also edit the configuration below to use some other directory.", diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorSecuritySetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorSecuritySetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorSecuritySetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorSecuritySetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -31,7 +31,7 @@ "\n\n". 'Upgrade %s to a patched version.'. "\n\n". - 'To learn more about how this issue affects Phabricator, see %s.', + 'To learn more about how this issue affects this software, see %s.', phutil_tag('tt', array(), 'bash'), phutil_tag('tt', array(), 'bash'), phutil_tag( @@ -61,7 +61,7 @@ 'Improve security by configuring an alternate file domain.')) ->setMessage( pht( - 'Phabricator is currently configured to serve user uploads '. + 'This software is currently configured to serve user uploads '. 'directly from the same domain as other content. This is a '. 'security risk.'. "\n\n". diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorStorageSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorStorageSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorStorageSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorStorageSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -83,7 +83,7 @@ $message = pht( 'When you upload a file via drag-and-drop or the API, chunks must '. 'be buffered into memory before being written to permanent '. - 'storage. Phabricator needs memory available to store these '. + 'storage. This server needs memory available to store these '. 'chunks while they are uploaded, but PHP is currently configured '. 'to severely limit the available memory.'. "\n\n". @@ -97,7 +97,7 @@ "The easiest way to resolve this issue is to set %s to %s in your ". "PHP configuration, to disable the memory limit. There is ". "usually little or no value to using this option to limit ". - "Phabricator process memory.". + "process memory.". "\n\n". "You can also increase the limit or ignore this issue and accept ". "that you may encounter problems uploading large files and ". diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorTimezoneSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorTimezoneSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorTimezoneSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorTimezoneSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,9 +40,10 @@ $message = pht( "Your configuration fails to specify a server timezone. You can either ". - "set the PHP configuration value '%s' or the Phabricator ". - "configuration value '%s' to specify one.", + "set the PHP configuration value '%s' or the %s configuration ". + "value '%s' to specify one.", 'date.timezone', + PlatformSymbols::getPlatformServerName(), 'phabricator.timezone'); $this diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorWebServerSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorWebServerSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/config/check/PhabricatorWebServerSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/check/PhabricatorWebServerSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -16,10 +16,10 @@ ->setSummary(pht('Pagespeed is enabled, but should be disabled.')) ->setMessage( pht( - 'Phabricator received an "X-Mod-Pagespeed" or "X-Page-Speed" '. + 'This server received an "X-Mod-Pagespeed" or "X-Page-Speed" '. 'HTTP header on this request, which indicates that you have '. 'enabled "mod_pagespeed" on this server. This module is not '. - 'compatible with Phabricator. You should disable it.')); + 'compatible with this software. You should disable the module.')); } $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); @@ -43,7 +43,7 @@ ->replaceQueryParam($expect_key, $expect_value); $self_future = id(new HTTPSFuture($base_uri)) - ->addHeader('X-Phabricator-SelfCheck', 1) + ->addHeader('X-Setup-SelfCheck', 1) ->addHeader('Accept-Encoding', 'gzip') ->setDisableContentDecoding(true) ->setHTTPBasicAuthCredentials( @@ -56,7 +56,7 @@ $gzip_compressed = gzencode($gzip_uncompressed); $gzip_future = id(new HTTPSFuture($base_uri)) - ->addHeader('X-Phabricator-SelfCheck', 1) + ->addHeader('X-Setup-SelfCheck', 1) ->addHeader('Content-Encoding', 'gzip') ->setTimeout(5) ->setData($gzip_compressed); @@ -91,9 +91,9 @@ $body = trim($body); if (preg_match('/^t2/', $body)) { $message = pht( - 'Phabricator appears to be installed on a very small EC2 instance '. + 'This software appears to be installed on a very small EC2 instance '. '(of class "%s") with burstable CPU. This is strongly discouraged. '. - 'Phabricator regularly needs CPU, and these instances are often '. + 'This software regularly needs CPU, and these instances are often '. 'choked to death by CPU throttling. Use an instance with a normal '. 'CPU instead.', $body); @@ -102,7 +102,7 @@ ->setName(pht('Installed on Burstable CPU Instance')) ->setSummary( pht( - 'Do not install Phabricator on an instance class with '. + 'Do not install this software on an instance class with '. 'burstable CPU.')) ->setMessage($message); } @@ -121,7 +121,7 @@ if (BaseHTTPFuture::getHeader($headers, 'Content-Encoding') != 'gzip') { $message = pht( - 'Phabricator sent itself a request with "Accept-Encoding: gzip", '. + 'This software sent itself a request with "Accept-Encoding: gzip", '. 'but received an uncompressed response.'. "\n\n". 'This may indicate that your webserver is not configured to '. @@ -163,8 +163,8 @@ ->truncateString($body); $message = pht( - 'Phabricator sent itself a test request with the '. - '"X-Phabricator-SelfCheck" header and expected to get a valid JSON '. + 'This software sent itself a test request with the '. + '"X-Setup-SelfCheck" header and expected to get a valid JSON '. 'response back. Instead, the response begins:'. "\n\n". '%s'. @@ -173,9 +173,9 @@ phutil_tag('pre', array(), $short)); } else { $message = pht( - 'Phabricator sent itself a test request and expected to get a bare '. - 'JSON response back. It received a JSON response, but the response '. - 'had extra whitespace at the beginning or end.'. + 'This software sent itself a test request and expected to get a '. + 'bare JSON response back. It received a JSON response, but the '. + 'response had extra whitespace at the beginning or end.'. "\n\n". 'This usually means you have edited a file and left whitespace '. 'characters before the opening %s tag, or after a closing %s tag. '. @@ -199,11 +199,11 @@ $actual_pass = idx($structure, 'pass'); if (($expect_user != $actual_user) || ($actual_pass != $expect_pass)) { $message = pht( - 'Phabricator sent itself a test request with an "Authorization" HTTP '. - 'header, and expected those credentials to be transmitted. However, '. - 'they were absent or incorrect when received. Phabricator sent '. - 'username "%s" with password "%s"; received username "%s" and '. - 'password "%s".'. + 'This software sent itself a test request with an "Authorization" '. + 'HTTP header, and expected those credentials to be transmitted. '. + 'However, they were absent or incorrect when received. This '. + 'software sent username "%s" with password "%s"; received '. + 'username "%s" and password "%s".'. "\n\n". 'Your webserver may not be configured to forward HTTP basic '. 'authentication. If you plan to use basic authentication (for '. @@ -222,13 +222,13 @@ $actual_path = idx($structure, 'path'); if ($expect_path != $actual_path) { $message = pht( - 'Phabricator sent itself a test request with an unusual path, to '. + 'This software sent itself a test request with an unusual path, to '. 'test if your webserver is rewriting paths correctly. The path was '. 'not transmitted correctly.'. "\n\n". - 'Phabricator sent a request to path "%s", and expected the webserver '. - 'to decode and rewrite that path so that it received a request for '. - '"%s". However, it received a request for "%s" instead.'. + 'This software sent a request to path "%s", and expected the '. + 'webserver to decode and rewrite that path so that it received a '. + 'request for "%s". However, it received a request for "%s" instead.'. "\n\n". 'Verify that your rewrite rules are configured correctly, following '. 'the instructions in the documentation. If path encoding is not '. @@ -258,12 +258,12 @@ if (($expect_key !== $actual_key) || ($expect_value !== $actual_value)) { $message = pht( - 'Phabricator sent itself a test request with an HTTP GET parameter, '. + 'This software sent itself a test request with an HTTP GET parameter, '. 'but the parameter was not transmitted. Sent "%s" with value "%s", '. 'got "%s" with value "%s".'. "\n\n". 'Your webserver is configured incorrectly and large parts of '. - 'Phabricator will not work until this issue is corrected.'. + 'this software will not work until this issue is corrected.'. "\n\n". '(This problem can be caused by a missing "QSA" in your RewriteRule.)', $expect_key, @@ -320,7 +320,7 @@ $message = array(); $message[] = pht( - 'Phabricator sent itself a test request that was compressed with '. + 'This software sent itself a test request that was compressed with '. '"Content-Encoding: gzip", but received different bytes than it '. 'sent.'); @@ -342,17 +342,17 @@ 'compressed requests.'); $message[] = pht( - 'The request body Phabricator sent began:'); + 'The request body that was sent began:'); $message[] = $this->snipBytes($compressed); $message[] = pht( - 'The request body Phabricator received began:'); + 'The request body that was received began:'); $message[] = $this->snipBytes($raw_body); } $message[] = pht( 'Identify the component in your webserver configuration which is '. - 'decompressing or mangling requests and disable it. Phabricator '. + 'decompressing or mangling requests and disable it. This software '. 'will not work properly until you do.'); $message = phutil_implode_html("\n\n", $message); diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/controller/module/PhabricatorConfigModuleController.php phabricator-0~git20220903/phabricator/src/applications/config/controller/module/PhabricatorConfigModuleController.php --- phabricator-0~git20200925/phabricator/src/applications/config/controller/module/PhabricatorConfigModuleController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/controller/module/PhabricatorConfigModuleController.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,7 +38,11 @@ $nav->selectFilter($key); $header = $this->buildHeaderView($title); - $view = $this->buildConfigBoxView($title, $content); + if ($content instanceof AphrontTableView) { + $view = $this->buildConfigBoxView($title, $content); + } else { + $view = $content; + } $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb(pht('Extensions/Modules'), $modules_uri) diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/controller/PhabricatorConfigConsoleController.php phabricator-0~git20220903/phabricator/src/applications/config/controller/PhabricatorConfigConsoleController.php --- phabricator-0~git20200925/phabricator/src/applications/config/controller/PhabricatorConfigConsoleController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/controller/PhabricatorConfigConsoleController.php 2022-06-14 16:29:55.000000000 +0000 @@ -56,7 +56,7 @@ ->setBorder(true); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Phabricator Configuation')) + ->setHeaderText(pht('Configuration')) ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setObjectList($menu); @@ -72,7 +72,7 @@ ->setFooter($launcher_view); return $this->newPage() - ->setTitle(pht('Phabricator Configuation')) + ->setTitle(pht('Configuration')) ->setCrumbs($crumbs) ->appendChild($view); } @@ -131,7 +131,7 @@ )); return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Phabricator Version Information')) + ->setHeaderText(pht('Version Information')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($table_view); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/controller/services/PhabricatorConfigClusterDatabasesController.php phabricator-0~git20220903/phabricator/src/applications/config/controller/services/PhabricatorConfigClusterDatabasesController.php --- phabricator-0~git20200925/phabricator/src/applications/config/controller/services/PhabricatorConfigClusterDatabasesController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/controller/services/PhabricatorConfigClusterDatabasesController.php 2022-06-14 16:29:55.000000000 +0000 @@ -207,7 +207,7 @@ $table = id(new AphrontTableView($rows)) ->setNoDataString( - pht('Phabricator is not configured in cluster mode.')) + pht('This server is not configured in cluster mode.')) ->setHeaders( array( null, diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/controller/settings/PhabricatorConfigEditController.php phabricator-0~git20220903/phabricator/src/applications/config/controller/settings/PhabricatorConfigEditController.php --- phabricator-0~git20200925/phabricator/src/applications/config/controller/settings/PhabricatorConfigEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/controller/settings/PhabricatorConfigEditController.php 2022-06-14 16:29:55.000000000 +0000 @@ -18,7 +18,7 @@ } else { $desc = pht( 'This configuration option is unknown. It may be misspelled, '. - 'or have existed in a previous version of Phabricator.'); + 'or have existed in a previous version of the software.'); } // This may be a dead config entry, which existed in the past but no diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/custom/PhabricatorCustomLogoConfigType.php phabricator-0~git20220903/phabricator/src/applications/config/custom/PhabricatorCustomLogoConfigType.php --- phabricator-0~git20200925/phabricator/src/applications/config/custom/PhabricatorCustomLogoConfigType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/custom/PhabricatorCustomLogoConfigType.php 2022-06-14 16:29:55.000000000 +0000 @@ -108,7 +108,7 @@ $controls[] = id(new AphrontFormTextControl()) ->setName('wordmarkText') ->setLabel(pht('Wordmark')) - ->setPlaceholder(pht('Phabricator')) + ->setPlaceholder(PlatformSymbols::getPlatformServerName()) ->setValue($wordmark_text); return $controls; diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/editor/PhabricatorConfigEditor.php phabricator-0~git20220903/phabricator/src/applications/config/editor/PhabricatorConfigEditor.php --- phabricator-0~git20200925/phabricator/src/applications/config/editor/PhabricatorConfigEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/editor/PhabricatorConfigEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,7 +8,7 @@ } public function getEditorObjectsDescription() { - return pht('Phabricator Configuration'); + return pht('Configuration'); } public function getTransactionTypes() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/issue/PhabricatorSetupIssue.php phabricator-0~git20220903/phabricator/src/applications/config/issue/PhabricatorSetupIssue.php --- phabricator-0~git20200925/phabricator/src/applications/config/issue/PhabricatorSetupIssue.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/issue/PhabricatorSetupIssue.php 2022-06-14 16:29:55.000000000 +0000 @@ -28,7 +28,8 @@ $message = pht( "Unable to connect to MySQL!\n\n". "%s\n\n". - "Make sure Phabricator and MySQL are correctly configured.", + "Make sure databases connection information and MySQL are ". + "correctly configured.", $ex->getMessage()); $issue = id(new self()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorAccessLogConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorAccessLogConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorAccessLogConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorAccessLogConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -73,8 +73,8 @@ ->setSummary(pht('Access log location.')) ->setDescription( pht( - "To enable the Phabricator access log, specify a path. The ". - "Phabricator access than normal HTTP access logs (for instance, ". + "To enable the HTTP access log, specify a path. This log is ". + "more detailed than normal HTTP access logs (for instance, ". "it can show logged-in users, controllers, and other application ". "data).\n\n". "If not set, no log will be written.")) @@ -82,7 +82,7 @@ null, pht('Disable access log.')) ->addExample( - '/var/log/phabricator/access.log', + '/var/log/devtools/access.log', pht('Write access log here.')), $this->newOption( 'log.access.format', @@ -98,16 +98,16 @@ ->setSummary(pht('SSH log location.')) ->setDescription( pht( - "To enable the Phabricator SSH log, specify a path. The ". - "access log can provide more detailed information about SSH ". - "access than a normal SSH log (for instance, it can show ". - "logged-in users, commands, and other application data).\n\n". + "To enable the SSH log, specify a path. This log can provide ". + "more detailed information about SSH access than a normal SSH ". + "log (for instance, it can show logged-in users, commands, and ". + "other application data).\n\n". "If not set, no log will be written.")) ->addExample( null, pht('Disable SSH log.')) ->addExample( - '/var/log/phabricator/ssh.log', + '/var/log/devtools/ssh.log', pht('Write SSH log here.')), $this->newOption( 'log.ssh.format', @@ -116,6 +116,20 @@ ->setLocked(true) ->setSummary(pht('SSH log format.')) ->setDescription($ssh_desc), + $this->newOption('log.ssh-error.path', 'string', null) + ->setLocked(true) + ->setSummary(pht('SSH error log location.')) + ->setDescription( + pht( + 'To enable the SSH error log, specify a path. Errors occurring '. + 'in contexts where this software is serving SSH requests '. + 'will be written to this log.'. + "\n\n". + 'If not set, no log will be written.')) + ->addExample(null, pht('Disable SSH error log.')) + ->addExample( + '/var/log/devtools/ssh-error.log', + pht('Write SSH error log here.')), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,14 +44,14 @@ pht('Require administrators to approve new accounts.')) ->setDescription( pht( - "Newly registered Phabricator accounts can either be placed ". + "Newly registered accounts can either be placed ". "into a manual approval queue for administrative review, or ". "automatically activated immediately. The approval queue is ". "enabled by default because it gives you greater control over ". - "who can register an account and access Phabricator.\n\n". + "who can register an account and access the server.\n\n". "If your install is completely public, or on a VPN, or users can ". "only register with a trusted provider like LDAP, or you've ". - "otherwise configured Phabricator to prevent unauthorized ". + "otherwise configured the server to prevent unauthorized ". "registration, you can disable the queue to reduce administrative ". "overhead.\n\n". "NOTE: Before you disable the queue, make sure ". @@ -107,7 +107,7 @@ 'This option controls whether users can edit account email '. 'addresses and profile real names.'. "\n\n". - 'If you set up Phabricator to automatically synchronize account '. + 'If you set things up to automatically synchronize account '. 'information from some other authoritative system, you can '. 'prevent users from making these edits to ensure information '. 'remains consistent across both systems.')), diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorAWSConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorAWSConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorAWSConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorAWSConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,7 +42,7 @@ pht( 'Explicit S3 endpoint to use. This should be the endpoint '. 'which corresponds to the region you have selected in '. - '`amazon-s3.region`. Phabricator can not determine the correct '. + '`amazon-s3.region`. This software can not determine the correct '. 'endpoint automatically because some endpoint locations are '. 'irregular.')) ->addExample( diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorClusterConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorClusterConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorClusterConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorClusterConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,7 +8,7 @@ } public function getDescription() { - return pht('Configure Phabricator to run on a cluster of hosts.'); + return pht('Configure services to run on a cluster of hosts.'); } public function getIcon() { @@ -25,7 +25,7 @@ WARNING: This is a prototype option and the description below is currently pure fantasy. -This option allows you to make Phabricator aware of database read replicas so +This option allows you to make this service aware of database read replicas so it can monitor database health, spread load, and degrade gracefully to read-only mode in the event of a failure on the primary host. For help with configuring cluster databases, see **[[ %s | %s ]]** in the documentation. @@ -55,7 +55,7 @@ ->setSummary(pht('Address ranges of cluster hosts.')) ->setDescription( pht( - 'Define a Phabricator cluster by providing a whitelist of host '. + 'Define a cluster by providing a whitelist of host '. 'addresses that are part of the cluster.'. "\n\n". 'Hosts on this whitelist have special powers. These hosts are '. @@ -67,7 +67,7 @@ 'cluster and no additional hosts. See the examples below for '. 'details.'. "\n\n". - 'When cluster addresses are defined, Phabricator hosts will also '. + 'When cluster addresses are defined, hosts will also '. 'reject requests to interfaces which are not whitelisted.', $intro_href, $intro_name)) @@ -101,7 +101,7 @@ 'hosting providers running multi-tenant clusters.'. "\n\n". 'If you provide an instance identifier here (normally by '. - 'injecting it with a `%s`), Phabricator will pass it to '. + 'injecting it with a `%s`), the server will pass it to '. 'subprocesses and commit hooks in the `%s` environmental variable.', 'PhabricatorConfigSiteSource', 'PHABRICATOR_INSTANCE')), @@ -115,7 +115,7 @@ 'WARNING: This is a prototype option and the description below '. 'is currently pure fantasy.'. "\n\n". - 'Switch Phabricator to read-only mode. In this mode, users will '. + 'Switch the service to read-only mode. In this mode, users will '. 'be unable to write new data. Normally, the cluster degrades '. 'into this mode automatically when it detects that the database '. 'master is unreachable, but you can activate it manually in '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorCoreConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorCoreConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorCoreConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorCoreConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,15 +38,15 @@ $applications_app_href = '/applications/'; $silent_description = $this->deformat(pht(<<<EOREMARKUP -This option allows you to stop Phabricator from sending data to most external +This option allows you to stop this service from sending data to most external services: it will disable email, SMS, repository mirroring, remote builds, Doorkeeper writes, and webhooks. -This option is intended to allow a Phabricator instance to be exported, copied, -imported, and run in a test environment without impacting users. For example, -if you are migrating to new hardware, you could perform a test migration first -with this flag set, make sure things work, and then do a production cutover -later with higher confidence and less disruption. +This option is intended to allow an instance to be exported, copied, imported, +and run in a test environment without impacting users. For example, if you are +migrating to new hardware, you could perform a test migration first with this +flag set, make sure things work, and then do a production cutover later with +higher confidence and less disruption. Without making use of this flag to silence the temporary test environment, users would receive duplicate email during the time the test instance and old @@ -72,35 +72,35 @@ return array( $this->newOption('phabricator.base-uri', 'string', null) ->setLocked(true) - ->setSummary(pht('URI where Phabricator is installed.')) + ->setSummary(pht('URI where this software is installed.')) ->setDescription( pht( - 'Set the URI where Phabricator is installed. Setting this '. + 'Set the URI where this software is installed. Setting this '. 'improves security by preventing cookies from being set on other '. 'domains, and allows daemons to send emails with links that have '. 'the correct domain.')) - ->addExample('http://phabricator.example.com/', pht('Valid Setting')), + ->addExample('http://devtools.example.com/', pht('Valid Setting')), $this->newOption('phabricator.production-uri', 'string', null) ->setSummary( pht('Primary install URI, for multi-environment installs.')) ->setDescription( pht( - 'If you have multiple Phabricator environments (like a '. - 'development/staging environment for working on testing '. - 'Phabricator, and a production environment for deploying it), '. + 'If you have multiple %s environments (like a '. + 'development/staging environment and a production environment), '. 'set the production environment URI here so that emails and other '. 'durable URIs will always generate with links pointing at the '. 'production environment. If unset, defaults to `%s`. Most '. 'installs do not need to set this option.', + PlatformSymbols::getPlatformServerName(), 'phabricator.base-uri')) - ->addExample('http://phabricator.example.com/', pht('Valid Setting')), + ->addExample('http://devtools.example.com/', pht('Valid Setting')), $this->newOption('phabricator.allowed-uris', 'list<string>', array()) ->setLocked(true) - ->setSummary(pht('Alternative URIs that can access Phabricator.')) + ->setSummary(pht('Alternative URIs that can access this service.')) ->setDescription( pht( "These alternative URIs will be able to access 'normal' pages ". - "on your Phabricator install. Other features such as OAuth ". + "on your this install. Other features such as OAuth ". "won't work. The major use case for this is moving installs ". "across domains.")) ->addExample( @@ -109,7 +109,7 @@ pht('Valid Setting')), $this->newOption('phabricator.timezone', 'string', null) ->setSummary( - pht('The timezone Phabricator should use.')) + pht('The timezone this software should use by default.')) ->setDescription($timezone_description) ->addExample('America/New_York', pht('US East (EDT)')) ->addExample('America/Chicago', pht('US Central (CDT)')) @@ -119,12 +119,12 @@ ->setLocked(true) ->setSummary( pht( - 'Set a string Phabricator should use to prefix cookie names.')) + 'Set a string this software should use to prefix cookie names.')) ->setDescription( pht( 'Cookies set for x.com are also sent for y.x.com. Assuming '. - 'Phabricator instances are running on both domains, this will '. - 'create a collision preventing you from logging in.')) + 'instances are running on both domains, this will create a '. + 'collision preventing you from logging in.')) ->addExample('dev', pht('Prefix cookie with "%s"', 'dev')), $this->newOption('phabricator.show-prototypes', 'bool', false) ->setLocked(true) @@ -141,11 +141,11 @@ "IMPORTANT: The upstream does not provide support for prototype ". "applications.". "\n\n". - "Phabricator includes prototype applications which are in an ". + "This platform includes prototype applications which are in an ". "**early stage of development**. By default, prototype ". "applications are not installed, because they are often not yet ". "developed enough to be generally usable. You can enable ". - "this option to install them if you're developing Phabricator ". + "this option to install them if you're developing applications ". "or are interested in previewing upcoming features.". "\n\n". "To learn more about prototypes, see [[ %s | %s ]].". @@ -164,18 +164,32 @@ pht('Allows you to remove levity and jokes from the UI.')) ->setDescription( pht( - 'By default, Phabricator includes some flavor text in the UI, '. + 'By default, this software includes some flavor text in the UI, '. 'like a prompt to "Weigh In" rather than "Add Comment" in '. 'Maniphest. If you\'d prefer more traditional UI strings like '. '"Add Comment", you can set this flag to disable most of the '. 'extra flavor.')), - $this->newOption('remarkup.ignored-object-names', 'string', '/^(Q|V)\d$/') + $this->newOption( + 'remarkup.ignored-object-names', + 'string', + + // Q1, Q2, etc., are common abbreviations for "Quarter". + // V1, V2, etc., are common abbreviations for "Version". + // P1, P2, etc., are common abbreviations for "Priority". + + // M1 is a computer chip manufactured by Apple. + // M2 (commonly spelled "M.2") is an expansion slot on motherboards. + // M4 is a carbine. + // M8 is a phonetic spelling of "mate", used in culturally significant + // copypasta about navy seals. + + '/^(Q|V|M|P)\d$/') ->setSummary( pht('Text values that match this regex and are also object names '. 'will not be linked.')) ->setDescription( pht( - 'By default, Phabricator links object names in Remarkup fields '. + 'By default, this software links object names in Remarkup fields '. 'to the corresponding object. This regex can be used to modify '. 'this behavior; object names that match this regex will not be '. 'linked.')), @@ -186,11 +200,11 @@ '$PATH')) ->setDescription( pht( - "Phabricator occasionally shells out to other binaries on the ". + "Thhi software sometimes executes other binaries on the ". "server. An example of this is the `%s` command, used to ". "syntax-highlight code written in languages other than PHP. By ". "default, it is assumed that these binaries are in the %s of the ". - "user running Phabricator (normally 'apache', 'httpd', or ". + "user running this software (normally 'apache', 'httpd', or ". "'nobody'). Here you can add extra directories to the %s ". "environment variable, for when these binaries are in ". "non-standard locations.\n\n". @@ -202,7 +216,7 @@ 'pygmentize', '$PATH', '$PATH', - 'phabricator/support/bin/', + 'support/bin/', $path)) ->setLocked(true) ->addExample('/usr/local/bin', pht('Add One Path')) @@ -237,7 +251,7 @@ $this->newOption('phabricator.application-settings', 'wild', array()) ->setLocked(true) ->setDescription( - pht('Customized settings for Phabricator applications.')), + pht('Customized settings for applications.')), $this->newOption('phabricator.cache-namespace', 'string', 'phabricator') ->setLocked(true) ->setDescription(pht('Cache namespace.')), @@ -248,7 +262,7 @@ pht('Run Silently'), pht('Run Normally'), )) - ->setSummary(pht('Stop Phabricator from sending any email, etc.')) + ->setSummary(pht('Stop this software from sending any email, etc.')) ->setDescription($silent_description), ); @@ -292,11 +306,11 @@ throw new PhabricatorConfigValidationException( pht( "Config option '%s' is invalid. The URI must NOT have a path, ". - "e.g. '%s' is OK, but '%s' is not. Phabricator must be installed ". - "on an entire domain; it can not be installed on a path.", + "e.g. '%s' is OK, but '%s' is not. This software must be '. + 'installed on an entire domain; it can not be installed on a path.", $key, - 'http://phabricator.example.com/', - 'http://example.com/phabricator/')); + 'http://devtools.example.com/', + 'http://example.com/devtools/')); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorDeveloperConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorDeveloperConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorDeveloperConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorDeveloperConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,7 +8,7 @@ } public function getDescription() { - return pht('Options for Phabricator developers, including debugging.'); + return pht('Options for platform developers, including debugging.'); } public function getIcon() { @@ -27,18 +27,19 @@ pht('Enable DarkConsole'), pht('Disable DarkConsole'), )) - ->setSummary(pht("Enable Phabricator's debugging console.")) + ->setSummary(pht('Enable the debugging console.')) ->setDescription( pht( "DarkConsole is a development and profiling tool built into ". - "Phabricator's web interface. You should leave it disabled unless ". - "you are developing or debugging Phabricator.\n\n". + "the web interface. You should leave it disabled unless ". + "you are developing or debugging %s.\n\n". "Once you activate DarkConsole for the install, **you need to ". "enable it for your account before it will actually appear on ". "pages.** You can do this in Settings > Developer Settings.\n\n". "DarkConsole exposes potentially sensitive data (like queries, ". "stack traces, and configuration) so you generally should not ". - "turn it on in production.")), + "turn it on in production.", + PlatformSymbols::getPlatformServerName())), $this->newOption('darkconsole.always-on', 'bool', false) ->setBoolOptions( array( @@ -91,11 +92,11 @@ 'Confirm before redirecting so DarkConsole can be examined.')) ->setDescription( pht( - 'Normally, Phabricator issues HTTP redirects after a successful '. + 'Normally, this software issues HTTP redirects after a successful '. 'POST. This can make it difficult to debug things which happen '. 'while processing the POST, because service and profiling '. 'information are lost. By setting this configuration option, '. - 'Phabricator will show a page instead of automatically '. + 'an interstitial page will be shown instead of automatically '. 'redirecting, allowing you to examine service and profiling '. 'information. It also makes the UX awful, so you should only '. 'enable it when debugging.')), @@ -106,7 +107,7 @@ ->setSummary(pht('Automatically profile some percentage of pages.')) ->setDescription( pht( - "Normally, Phabricator profiles pages only when explicitly ". + "Normally, pages are profiled only when explicitly ". "requested via DarkConsole. However, it may be useful to profile ". "some pages automatically.\n\n". "Set this option to a positive integer N to profile 1 / N pages ". @@ -128,7 +129,7 @@ ->setDescription( pht( "The Multimeter application collects performance samples. You ". - "can use this data to help you understand what Phabricator is ". + "can use this data to help you understand what the software is ". "spending time and resources doing, and to identify problematic ". "access patterns.". "\n\n". diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,11 +4,11 @@ extends PhabricatorApplicationConfigOptions { public function getName() { - return pht('Extending Phabricator'); + return pht('Extensions'); } public function getDescription() { - return pht('Make Phabricator even cooler!'); + return pht('Manage extensions.'); } public function getIcon() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,33 +22,32 @@ public function getOptions() { $send_as_user_desc = $this->deformat(pht(<<<EODOC When a user takes an action which generates an email notification (like -commenting on a Differential revision), Phabricator can either send that mail -"From" the user's email address (like "alincoln@logcabin.com") or "From" the -'%s' address. - -The user experience is generally better if Phabricator uses the user's real -address as the "From" since the messages are easier to organize when they appear -in mail clients, but this will only work if the server is authorized to send -email on behalf of the "From" domain. Practically, this means: +commenting on a Differential revision), the "From" address can either be set +to the user's email address (like "alincoln@logcabin.com") or the +"metamta.defualt-address" address. + +The user experience is generally better if the user's real address is used as +the "From" header value, since the messages are easier to organize when they +appear in mail clients, but this will only work if the server is authorized to +send email on behalf of the "From" domain. Practically, this means: - If you are doing an install for Example Corp and all the users will have - corporate @corp.example.com addresses and any hosts Phabricator is running + corporate @corp.example.com addresses and any hosts this software is running on are authorized to send email from corp.example.com, you can enable this to make the user experience a little better. - If you are doing an install for an open source project and your users will - be registering via Facebook and using personal email addresses, you probably - should not enable this or all of your outgoing email might vanish into SFP - blackholes. + be registering via third-party services and/or using personal email + addresses, you probably should not enable this or all of your outgoing + email might vanish into SFP blackholes. - If your install is anything else, you're safer leaving this off, at least initially, since the risk in turning it on is that your outgoing mail will never arrive. EODOC - , - 'metamta.default-address')); + )); $one_mail_per_recipient_desc = $this->deformat(pht(<<<EODOC When a message is sent to multiple recipients (for example, several reviewers on -a code review), Phabricator can either deliver one email to everyone (e.g., "To: +a code review), it can either be delieverd as one email to everyone (e.g., "To: alincoln, usgrant, htaft") or separate emails to each user (e.g., "To: alincoln", "To: usgrant", "To: htaft"). The major advantages and disadvantages of each approach are: @@ -62,7 +61,7 @@ - Getting threading to work properly is harder, and probably requires making mail less useful by turning off options. - Sometimes people will "Reply All", which can send mail to too many - recipients. Phabricator will try not to send mail to users who already + recipients. This software will try not to send mail to users who already received a similar message, but can not prevent all stray email arising from "Reply All". - Not supported with a private reply-to address. @@ -104,7 +103,7 @@ $re_prefix_description = $this->deformat(pht(<<<EODOC Mail.app on OS X Lion won't respect threading headers unless the subject is -prefixed with "Re:". If you enable this option, Phabricator will add "Re:" to +prefixed with "Re:". If you enable this option, this software will add "Re:" to the subject line of all mail which is expected to thread. If you've set 'metamta.one-mail-per-recipient', users can override this setting in their preferences. @@ -121,7 +120,7 @@ 'metamta.one-mail-per-recipient')); $reply_to_description = $this->deformat(pht(<<<EODOC -If you enable `%s`, Phabricator uses "From" to authenticate users. You can +If you enable `%s`, this software uses "From" to authenticate users. You can additionally enable this setting to try to authenticate with 'Reply-To'. Note that this is completely spoofable and insecure (any user can set any 'Reply-To' address) but depending on the nature of your install or other deliverability @@ -142,33 +141,33 @@ )); $public_replies_description = $this->deformat(pht(<<<EODOC -By default, Phabricator generates unique reply-to addresses and sends a separate -email to each recipient when you enable reply handling. This is more secure than -using "From" to establish user identity, but can mean users may receive multiple -emails when they are on mailing lists. Instead, you can use a single, non-unique -reply to address and authenticate users based on the "From" address by setting -this to 'true'. This trades away a little bit of security for convenience, but -it's reasonable in many installs. Object interactions are still protected using -hashes in the single public email address, so objects can not be replied to -blindly. +By default, this software generates unique reply-to addresses and sends a +separate email to each recipient when you enable reply handling. This is more +secure than using "From" to establish user identity, but can mean users may +receive multiple emails when they are on mailing lists. Instead, you can use a +single, non-unique reply to address and authenticate users based on the "From" +address by setting this to 'true'. This trades away a little bit of security +for convenience, but it's reasonable in many installs. Object interactions are +still protected using hashes in the single public email address, so objects +can not be replied to blindly. EODOC )); $single_description = $this->deformat(pht(<<<EODOC -If you want to use a single mailbox for Phabricator reply mail, you can use this -and set a common prefix for reply addresses generated by Phabricator. It will +If you want to use a single mailbox for reply mail, you can use this +and set a common prefix for generated reply addresses. It will make use of the fact that a mail-address such as -`phabricator+D123+1hjk213h@example.com` will be delivered to the `phabricator` +`devtools+D123+1hjk213h@example.com` will be delivered to the `devtools` user's mailbox. Set this to the left part of the email address and it will be prepended to all generated reply addresses. -For example, if you want to use `phabricator@example.com`, this should be set -to `phabricator`. +For example, if you want to use `devtools@example.com`, this should be set +to `devtools`. EODOC )); $address_description = $this->deformat(pht(<<<EODOC -When email is sent, what format should Phabricator use for user's email +When email is sent, what format should the software use for users' email addresses? Valid values are: - `short`: 'gwashington <gwashington@example.com>' @@ -192,12 +191,12 @@ required but no meaningful address is available. If you configure inbound mail, you generally do not need to set this: -Phabricator will automatically generate and use a suitable mailbox on the +the software will automatically generate and use a suitable mailbox on the inbound mail domain. Otherwise, this option should be configured to point at a valid mailbox which discards all mail sent to it. If you point it at an invalid mailbox, mail sent -by Phabricator and some mail sent by users will bounce. If you point it at a +by the software and some mail sent by users will bounce. If you point it at a real user mailbox, that user will get a lot of mail they don't want. For further guidance, see **[[ %s | %s ]]** in the documentation. @@ -226,19 +225,22 @@ )) ->setSummary( pht( - 'Controls whether Phabricator sends one email with multiple '. - 'recipients in the "To:" line, or multiple emails, each with a '. - 'single recipient in the "To:" line.')) + 'Controls whether email for multiple recipients is sent by '. + 'creating one message with everyone in the "To:" line, or '. + 'multiple messages that each have a single recipeint in the '. + '"To:" line.')) ->setDescription($one_mail_per_recipient_desc), $this->newOption('metamta.can-send-as-user', 'bool', false) ->setBoolOptions( array( pht('Send as User Taking Action'), - pht('Send as Phabricator'), + pht( + 'Send as %s', + PlatformSymbols::getPlatformServerName()), )) ->setSummary( pht( - 'Controls whether Phabricator sends email "From" users.')) + 'Controls whether email is sent "From" users.')) ->setDescription($send_as_user_desc), $this->newOption( 'metamta.reply-handler-domain', @@ -246,7 +248,7 @@ null) ->setLocked(true) ->setDescription(pht('Domain used for reply email addresses.')) - ->addExample('phabricator.example.com', ''), + ->addExample('devtools.example.com', ''), $this->newOption('metamta.recipients.show-hints', 'bool', true) ->setBoolOptions( array( @@ -271,12 +273,12 @@ )) ->setSummary( pht( - 'Phabricator can use less-secure but mailing list friendly public '. - 'reply addresses.')) + 'Reply addresses can either be private (more secure) or '. + 'public (which works better with mailing lists).')) ->setDescription($public_replies_description), $this->newOption('metamta.single-reply-handler-prefix', 'string', null) ->setSummary( - pht('Allow Phabricator to use a single mailbox for all replies.')) + pht('Allow a single mailbox to be used for all replies.')) ->setDescription($single_description), $this->newOption('metamta.user-address-format', 'enum', 'full') ->setEnumOptions( @@ -285,7 +287,7 @@ 'real' => pht('Real'), 'full' => pht('Full'), )) - ->setSummary(pht('Control how Phabricator renders user names in mail.')) + ->setSummary(pht('Control how user names are rendered in mail.')) ->setDescription($address_description) ->addExample('gwashington <gwashington@example.com>', 'short') ->addExample('George Washington <gwashington@example.com>', 'real') diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorMySQLConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorMySQLConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorMySQLConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorMySQLConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,14 +38,14 @@ $this->newOption('storage.default-namespace', 'string', 'phabricator') ->setLocked(true) ->setSummary( - pht('The namespace that Phabricator databases should use.')) + pht('The namespace that databases should use.')) ->setDescription( pht( - "Phabricator puts databases in a namespace, which defaults to ". + "Databases are created in a namespace, which defaults to ". "'phabricator' -- for instance, the Differential database is ". "named 'phabricator_differential' by default. You can change ". "this namespace if you want. Normally, you should not do this ". - "unless you are developing Phabricator and using namespaces to ". + "unless you are developing extensions and using namespaces to ". "separate multiple sandbox datasets.")), $this->newOption('mysql.port', 'string', null) ->setLocked(true) diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorPHDConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorPHDConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorPHDConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorPHDConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -50,7 +50,7 @@ pht( 'Specify a system user to run the daemons as. Primarily, this '. 'user will own the working copies of any repositories that '. - 'Phabricator imports or manages. This option is new and '. + 'this software imports or manages. This option is new and '. 'experimental.')), $this->newOption('phd.garbage-collection', 'wild', array()) ->setLocked(true) diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorSecurityConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorSecurityConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorSecurityConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorSecurityConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -67,7 +67,7 @@ PhabricatorEnv::getDoclink('Configuring Encryption'))); $require_mfa_description = $this->deformat(pht(<<<EOTEXT -By default, Phabricator allows users to add multi-factor authentication to +By default, this software allows users to add multi-factor authentication to their accounts, but does not require it. By enabling this option, you can force all users to add at least one authentication factor before they can use their accounts. @@ -87,7 +87,7 @@ ->setSummary(pht('Alternate domain to serve files from.')) ->setDescription( pht( - 'By default, Phabricator serves files from the same domain '. + 'By default, this software serves files from the same domain '. 'the application is served from. This is convenient, but '. 'presents a security risk.'. "\n\n". @@ -119,7 +119,7 @@ pht( "If the web server responds to both HTTP and HTTPS requests but ". "you want users to connect with only HTTPS, you can set this ". - "to `true` to make Phabricator redirect HTTP requests to HTTPS.". + "to `true` to make this service redirect HTTP requests to HTTPS.". "\n\n". "Normally, you should just configure your server not to accept ". "HTTP traffic, but this setting may be useful if you originally ". @@ -128,15 +128,14 @@ "balancer which terminates HTTPS connections and you can not ". "reasonably configure more granular behavior there.". "\n\n". - "IMPORTANT: Phabricator determines if a request is HTTPS or not ". - "by examining the PHP `%s` variable. If you run ". - "Apache/mod_php this will probably be set correctly for you ". - "automatically, but if you run Phabricator as CGI/FCGI (e.g., ". - "through nginx or lighttpd), you need to configure your web ". - "server so that it passes the value correctly based on the ". - "connection type.". + "IMPORTANT: A request is identified as HTTP or HTTPS by examining ". + "the PHP `%s` variable. If you run Apache/mod_php this will ". + "probably be set correctly for you automatically, but if you run ". + "as CGI/FCGI (e.g., through nginx or lighttpd), you need to ". + "configure your web server so that it passes the value correctly ". + "based on the connection type.". "\n\n". - "If you configure Phabricator in cluster mode, note that this ". + "If you configure clustering, note that this ". "setting is ignored by intracluster requests.", "\$_SERVER['HTTPS']")) ->setBoolOptions( @@ -177,12 +176,12 @@ 'dangerous URI handlers.'. "\n\n". 'This set is also used to enforce valid redirect URIs. '. - 'Phabricator will refuse to issue a HTTP "Location" redirect to a '. - 'URI with a protocol not on this set.'. + 'This service will refuse to issue a HTTP "Location" redirect '. + 'to a URI with a protocol not on this set.'. "\n\n". 'Usually, "http" and "https" should be present in this set. If '. - 'you remove one or both protocols, some Phabricator features '. - 'which rely on links or redirects may not work.')) + 'you remove one or both protocols, some features which rely on '. + 'links or redirects may not work.')) ->addExample("http\nhttps", pht('Valid Setting')) ->setLocked(true), $this->newOption( @@ -248,10 +247,9 @@ 'requests.')) ->setDescription( pht( - 'Phabricator users can make requests to other services from '. - 'the Phabricator host in some circumstances (for example, by '. - 'creating a repository with a remote URL or having Phabricator '. - 'fetch an image from a remote server).'. + 'Users can make requests to other services from '. + 'service hosts in some circumstances (for example, by '. + 'creating a repository with a remote URL).'. "\n\n". 'This may represent a security vulnerability if services on '. 'the same subnet will accept commands or reveal private '. @@ -259,8 +257,8 @@ 'IP address. In particular, all hosts in EC2 have access to '. 'such a service.'. "\n\n". - 'This option defines a list of netblocks which Phabricator '. - 'will decline to connect to. Generally, you should list all '. + 'This option defines a list of netblocks which requests will '. + 'never be issued to. Generally, you should list all '. 'private IP space here.')) ->addExample(array('0.0.0.0/0'), pht('No Outbound Requests')), $this->newOption('security.strict-transport-security', 'bool', false) @@ -326,11 +324,11 @@ throw new PhabricatorConfigValidationException( pht( "Config option '%s' is invalid. The URI must NOT have a path, ". - "e.g. '%s' is OK, but '%s' is not. Phabricator must be installed ". - "on an entire domain; it can not be installed on a path.", + "e.g. '%s' is OK, but '%s' is not. This software must be ". + "installed on an entire domain; it can not be installed on a path.", $key, - 'http://phabricator.example.com/', - 'http://example.com/phabricator/')); + 'http://devtools.example.com/', + 'http://example.com/devtools/')); } } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -31,13 +31,12 @@ ->setSummary(pht('Default non-pygments syntax highlighter engine.')) ->setDescription( pht( - 'Phabricator can highlight PHP by default and use Pygments for '. - 'other languages if enabled. You can provide a custom '. - 'highlighter engine by extending class %s.', + 'You can provide a custom highlighter engine by extending '. + 'class %s.', 'PhutilSyntaxHighlighterEngine')), $this->newOption('pygments.enabled', 'bool', false) ->setSummary( - pht('Should Phabricator use Pygments to highlight code?')) + pht('Use Pygments to highlight code?')) ->setBoolOptions( array( pht('Use Pygments'), @@ -45,7 +44,7 @@ )) ->setDescription( pht( - 'Phabricator supports syntax highlighting a few languages by '. + 'Syntax highlighting a supported for a few languages by '. 'default, but you can install Pygments (a third-party syntax '. 'highlighting tool) to provide support for many more languages.'. "\n\n". @@ -54,12 +53,12 @@ 'download and install instructions.'. "\n\n". 'Once Pygments is installed, enable this option '. - '(`pygments.enabled`) to make Phabricator use Pygments when '. + '(`pygments.enabled`) to make use of Pygments when '. 'highlighting source code.'. "\n\n". 'After you install and enable Pygments, newly created source '. 'code (like diffs and pastes) should highlight correctly. '. - 'You may need to clear Phabricator\'s caches to get previously '. + 'You may need to clear caches to get previously '. 'existing source code to highlight. For instructions on '. 'managing caches, see [[ %s | Managing Caches ]].', $caches_href)), diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorUIConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorUIConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/config/option/PhabricatorUIConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/option/PhabricatorUIConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,7 +8,7 @@ } public function getDescription() { - return pht('Configure the Phabricator UI, including colors.'); + return pht('Configure the UI, including colors.'); } public function getIcon() { @@ -51,7 +51,7 @@ return array( $this->newOption('ui.header-color', 'enum', 'blindigo') ->setDescription( - pht('Sets the default color scheme of Phabricator.')) + pht('Sets the default color scheme.')) ->setEnumOptions($options), $this->newOption('ui.logo', $logo_type, array()) ->setSummary( @@ -61,9 +61,10 @@ "Customize the logo image and text which appears in the main ". "site header:\n\n". " - **Logo Image**: Upload a new 80 x 80px image to replace the ". - "Phabricator logo in the site header.\n\n". + "logo in the site header.\n\n". " - **Wordmark**: Choose new text to display next to the logo. ". - "By default, the header displays //Phabricator//.\n\n")), + "By default, the header displays //%s//.\n\n", + PlatformSymbols::getPlatformServerName())), $this->newOption('ui.favicons', 'wild', array()) ->setSummary(pht('Customize favicons.')) ->setDescription(pht('Customize favicons.')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/response/PhabricatorConfigResponse.php phabricator-0~git20220903/phabricator/src/applications/config/response/PhabricatorConfigResponse.php --- phabricator-0~git20200925/phabricator/src/applications/config/response/PhabricatorConfigResponse.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/response/PhabricatorConfigResponse.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ } protected function getResponseTitle() { - return pht('Phabricator Setup Error'); + return pht('Setup Error'); } protected function getResponseBodyClass() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php phabricator-0~git20220903/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php --- phabricator-0~git20200925/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/config/view/PhabricatorSetupIssueView.php 2022-06-14 16:29:55.000000000 +0000 @@ -90,14 +90,14 @@ $fallback_info = pht( "If those commands don't work, try Google. The process of installing ". - "PHP extensions is not specific to Phabricator, and any instructions ". - "you can find for installing them on your system should work. On Mac ". - "OS X, you might want to try Homebrew."); + "PHP extensions is not specific to this software, and any ". + "instructions you can find for installing them on your system should ". + "work. On Mac OS X, you might want to try Homebrew."); $restart_info = pht( - 'After installing new PHP extensions, <strong>restart Phabricator '. + 'After installing new PHP extensions, <strong>restart everything '. 'for the changes to take effect</strong>. For help with restarting '. - 'Phabricator, see %s in the documentation.', + 'everything, see %s in the documentation.', $this->renderRestartLink()); $description[] = phutil_tag( @@ -249,7 +249,7 @@ 'p', array(), pht( - 'The current Phabricator configuration has these %d value(s):', + 'The current configuration has these %d value(s):', count($configs))); $options = PhabricatorApplicationConfigOptions::loadAllOptions(); @@ -284,7 +284,7 @@ $update = array(); foreach ($configs as $key) { $update[] = hsprintf( - '<tt>phabricator/ $</tt> ./bin/config set %s <em>value</em>', + '<tt>$</tt> ./bin/config set %s <em>value</em>', $key); } $update = phutil_tag('pre', array(), phutil_implode_html("\n", $update)); @@ -460,9 +460,9 @@ 'p', array(), pht( - 'After editing the PHP configuration, <strong>restart Phabricator for '. + 'After editing the PHP configuration, <strong>restart everything for '. 'the changes to take effect</strong>. For help with restarting '. - 'Phabricator, see %s in the documentation.', + 'everything, see %s in the documentation.', $this->renderRestartLink())); return phutil_tag( diff -Nru phabricator-0~git20200925/phabricator/src/applications/console/plugin/DarkConsoleEventPlugin.php phabricator-0~git20220903/phabricator/src/applications/console/plugin/DarkConsoleEventPlugin.php --- phabricator-0~git20200925/phabricator/src/applications/console/plugin/DarkConsoleEventPlugin.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/console/plugin/DarkConsoleEventPlugin.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,7 +7,7 @@ } public function getDescription() { - return pht('Information about Phabricator events and event listeners.'); + return pht('Information about events and event listeners.'); } public function generateData() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/countdown/query/PhabricatorCountdownQuery.php phabricator-0~git20220903/phabricator/src/applications/countdown/query/PhabricatorCountdownQuery.php --- phabricator-0~git20200925/phabricator/src/applications/countdown/query/PhabricatorCountdownQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/countdown/query/PhabricatorCountdownQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -28,10 +28,6 @@ return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - public function newResultObject() { return new PhabricatorCountdown(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/daemon/application/PhabricatorDaemonsApplication.php phabricator-0~git20220903/phabricator/src/applications/daemon/application/PhabricatorDaemonsApplication.php --- phabricator-0~git20200925/phabricator/src/applications/daemon/application/PhabricatorDaemonsApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/daemon/application/PhabricatorDaemonsApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,7 +7,7 @@ } public function getShortDescription() { - return pht('Manage Phabricator Daemons'); + return pht('Manage Daemons'); } public function getBaseURI() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/daemon/event/PhabricatorDaemonEventListener.php phabricator-0~git20220903/phabricator/src/applications/daemon/event/PhabricatorDaemonEventListener.php --- phabricator-0~git20200925/phabricator/src/applications/daemon/event/PhabricatorDaemonEventListener.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/daemon/event/PhabricatorDaemonEventListener.php 2022-06-14 16:29:55.000000000 +0000 @@ -63,9 +63,12 @@ // TODO: This is a bit awkward for historical reasons, clean it up after // removing Conduit. $message = $event->getValue('message'); + $context = $event->getValue('context'); - if (strlen($context) && $context !== $message) { - $message = "({$context}) {$message}"; + if (phutil_nonempty_scalar($context)) { + if ($context !== $message) { + $message = "({$context}) {$message}"; + } } $type = $event->getValue('type'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementRestartWorkflow.php phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementRestartWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementRestartWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementRestartWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -24,7 +24,7 @@ 'name' => 'force', 'help' => pht( 'Stop all daemon processes on this host, even if they belong '. - 'to another Phabricator instance.'), + 'to another instance.'), ), array( 'name' => 'gently', diff -Nru phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStartWorkflow.php phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStartWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStartWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStartWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,7 +8,7 @@ ->setName('start') ->setSynopsis( pht( - 'Start the standard configured collection of Phabricator daemons. '. + 'Start the standard configured collection of daemons. '. 'This is appropriate for most installs. Use **%s** to '. 'customize which daemons are launched.', 'phd launch')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStopWorkflow.php phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStopWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStopWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementStopWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ 'name' => 'force', 'help' => pht( 'Stop all daemon processes on this host, even if they belong '. - 'to another Phabricator instance.'), + 'to another instance.'), ), array( 'name' => 'gently', diff -Nru phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementWorkflow.php phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/daemon/management/PhabricatorDaemonManagementWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -93,7 +93,7 @@ pht( "You are trying to run a daemon as a nonstandard user, ". "and `%s` was not able to `%s` to the correct user. \n". - 'Phabricator is configured to run daemons as "%s", '. + 'The daemons are configured to run as "%s", '. 'but the current user is "%s". '."\n". 'Use `%s` to run as a different user, pass `%s` to ignore this '. 'warning, or edit `%s` to change the configuration.', @@ -154,7 +154,7 @@ SIGINT, array(__CLASS__, 'ignoreSignal')); - echo "\n phabricator/scripts/daemon/ \$ {$command}\n\n"; + echo "\n scripts/daemon/ \$ {$command}\n\n"; $tempfile = new TempFile('daemon.config'); Filesystem::writeFile($tempfile, json_encode($config)); @@ -579,7 +579,7 @@ $console->writeErr( "%s\n", pht( - 'PID "%d" is not a known Phabricator daemon PID.', + 'PID "%d" is not a known daemon PID.', $pid)); continue; } else { diff -Nru phabricator-0~git20200925/phabricator/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php phabricator-0~git20220903/phabricator/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -71,6 +71,17 @@ return $panel; } + protected function newEditableObjectForDocumentation() { + $panel = parent::newEditableObjectForDocumentation(); + + $text_type = id(new PhabricatorDashboardTextPanelType()) + ->getPanelTypeKey(); + + $panel->setPanelType($text_type); + + return $panel; + } + protected function newObjectQuery() { return new PhabricatorDashboardPanelQuery(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php phabricator-0~git20220903/phabricator/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php --- phabricator-0~git20200925/phabricator/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -140,8 +140,7 @@ return $this->renderErrorPanel( $panel->getName(), pht( - 'This panel has type "%s", but that panel type is not known to '. - 'Phabricator.', + 'This panel has type "%s", but that panel type is unknown.', $panel->getPanelType())); } @@ -425,8 +424,9 @@ throw new Exception( pht( 'To render more than %s levels of panels nested inside other '. - 'panels, purchase a subscription to Phabricator Gold.', - new PhutilNumber($max_depth))); + 'panels, purchase a subscription to %s Gold.', + new PhutilNumber($max_depth), + PlatformSymbols::getPlatformServerName())); } if (in_array($panel->getPHID(), $this->parentPanelPHIDs)) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php phabricator-0~git20220903/phabricator/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php --- phabricator-0~git20200925/phabricator/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php 2022-06-14 16:29:55.000000000 +0000 @@ -194,7 +194,7 @@ if (!$engine) { throw new Exception( pht( - 'The application search engine "%s" is not known to Phabricator!', + 'The application search engine "%s" is unknown.', $class)); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php phabricator-0~git20220903/phabricator/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php --- phabricator-0~git20200925/phabricator/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,10 +34,6 @@ return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - public function newResultObject() { // TODO: If we don't do this, SearchEngine explodes when trying to // enumerate custom fields. For now, just give the panel a default panel diff -Nru phabricator-0~git20200925/phabricator/src/applications/dashboard/query/PhabricatorDashboardPortalQuery.php phabricator-0~git20220903/phabricator/src/applications/dashboard/query/PhabricatorDashboardPortalQuery.php --- phabricator-0~git20200925/phabricator/src/applications/dashboard/query/PhabricatorDashboardPortalQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/dashboard/query/PhabricatorDashboardPortalQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorDashboardPortal(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/dashboard/query/PhabricatorDashboardQuery.php phabricator-0~git20220903/phabricator/src/applications/dashboard/query/PhabricatorDashboardQuery.php --- phabricator-0~git20200925/phabricator/src/applications/dashboard/query/PhabricatorDashboardQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/dashboard/query/PhabricatorDashboardQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,10 +34,6 @@ return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - public function newResultObject() { return new PhabricatorDashboard(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/dashboard/storage/PhabricatorDashboardPanel.php phabricator-0~git20220903/phabricator/src/applications/dashboard/storage/PhabricatorDashboardPanel.php --- phabricator-0~git20200925/phabricator/src/applications/dashboard/storage/PhabricatorDashboardPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/dashboard/storage/PhabricatorDashboardPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -96,8 +96,7 @@ throw new Exception( pht( 'Attempting to use a panel in a way that requires an '. - 'implementation, but the panel implementation ("%s") is unknown to '. - 'Phabricator.', + 'implementation, but the panel implementation ("%s") is unknown.', $this->getPanelType())); } return $impl; diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/application/PhabricatorDifferentialApplication.php phabricator-0~git20220903/phabricator/src/applications/differential/application/PhabricatorDifferentialApplication.php --- phabricator-0~git20200925/phabricator/src/applications/differential/application/PhabricatorDifferentialApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/application/PhabricatorDifferentialApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -74,6 +74,8 @@ => 'DifferentialRevisionOperationController', 'inlines/(?P<id>[1-9]\d*)/' => 'DifferentialRevisionInlinesController', + 'paths/(?P<id>[1-9]\d*)/' + => 'DifferentialRevisionAffectedPathsController', ), 'comment/' => array( 'inline/' => array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/conduit/DifferentialChangesetSearchConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/differential/conduit/DifferentialChangesetSearchConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/differential/conduit/DifferentialChangesetSearchConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/conduit/DifferentialChangesetSearchConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,18 @@ +<?php + +final class DifferentialChangesetSearchConduitAPIMethod + extends PhabricatorSearchEngineAPIMethod { + + public function getAPIMethodName() { + return 'differential.changeset.search'; + } + + public function newSearchEngine() { + return new DifferentialChangesetSearchEngine(); + } + + public function getMethodSummary() { + return pht('Read information about changesets.'); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -100,7 +100,7 @@ ->setChangesetID($cid) ->setAuthorPHID($request->getUser()->getPHID()) ->setContent($request->getValue('content')) - ->setIsNewFile($request->getValue('isNewFile')) + ->setIsNewFile((int)$request->getValue('isNewFile')) ->setLineNumber($request->getValue('lineNumber')) ->setLineLength($request->getValue('lineLength', 0)) ->save(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/conduit/DifferentialQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,7 +38,7 @@ 'authors' => 'optional list<phid>', 'ccs' => 'optional list<phid>', 'reviewers' => 'optional list<phid>', - 'paths' => 'optional list<pair<callsign, path>>', + 'paths' => 'unsupported', 'commitHashes' => 'optional list<pair<'.$hash_const.', string>>', 'status' => 'optional '.$status_const, 'order' => 'optional '.$order_const, @@ -92,48 +92,11 @@ } if ($path_pairs) { - $paths = array(); - foreach ($path_pairs as $pair) { - list($callsign, $path) = $pair; - $paths[] = $path; - } - - $path_map = id(new DiffusionPathIDQuery($paths))->loadPathIDs(); - if (count($path_map) != count($paths)) { - $unknown_paths = array(); - foreach ($paths as $p) { - if (!idx($path_map, $p)) { - $unknown_paths[] = $p; - } - } - throw id(new ConduitException('ERR-INVALID-PARAMETER')) - ->setErrorDescription( - pht( - 'Unknown paths: %s', - implode(', ', $unknown_paths))); - } - - $repos = array(); - foreach ($path_pairs as $pair) { - list($callsign, $path) = $pair; - if (!idx($repos, $callsign)) { - $repos[$callsign] = id(new PhabricatorRepositoryQuery()) - ->setViewer($request->getUser()) - ->withCallsigns(array($callsign)) - ->executeOne(); - - if (!$repos[$callsign]) { - throw id(new ConduitException('ERR-INVALID-PARAMETER')) - ->setErrorDescription( - pht( - 'Unknown repo callsign: %s', - $callsign)); - } - } - $repo = $repos[$callsign]; - - $query->withPath($repo->getID(), idx($path_map, $path)); - } + throw new Exception( + pht( + 'Parameter "paths" to Conduit API method "differential.query" is '. + 'no longer supported. Use the "paths" constraint to '. + '"differential.revision.search" instead. See T13639.')); } if ($commit_hashes) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -210,8 +210,8 @@ 'to "Close" the revision and move it off the dashboard.'. "\n\n". 'If you have an unusual workflow where Differential is used for '. - 'post-commit review (normally called "Audit", elsewhere in '. - 'Phabricator), you can set this flag to treat the "Accepted" '. + 'post-commit review (normally called "Audit", elsewhere), you '. + 'can set this flag to treat the "Accepted" '. 'state as a "Closed" state and end the review workflow early.'. "\n\n". 'This sort of workflow is very unusual. Very few installs should '. @@ -228,7 +228,7 @@ ->setSummary(pht('Attach patches to email, as text attachments.')) ->setDescription( pht( - 'If you set this to true, Phabricator will attach patches to '. + 'If you set this to true, patches will be attached to '. 'Differential mail (as text attachments). This will not work if '. 'you are using SendGrid as your mail adapter.')), $this->newOption( diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/constants/DifferentialConstantsModule.php phabricator-0~git20220903/phabricator/src/applications/differential/constants/DifferentialConstantsModule.php --- phabricator-0~git20200925/phabricator/src/applications/differential/constants/DifferentialConstantsModule.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/constants/DifferentialConstantsModule.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,180 @@ +<?php + +final class DifferentialConstantsModule + extends PhabricatorConfigModule { + + public function getModuleKey() { + return 'constants.differential'; + } + + public function getModuleName() { + return pht('Constants: Differential'); + } + + public function renderModuleStatus(AphrontRequest $request) { + $viewer = $request->getViewer(); + + return array( + $this->renderRevisionStatuses($viewer), + $this->renderUnitStatuses($viewer), + $this->renderLintStatuses($viewer), + ); + } + + private function renderRevisionStatuses(PhabricatorUser $viewer) { + $statuses = DifferentialRevisionStatus::getAll(); + + $rows = array(); + foreach ($statuses as $status) { + $icon = id(new PHUIIconView()) + ->setIcon( + $status->getIcon(), + $status->getIconColor()); + + $timeline_icon = $status->getTimelineIcon(); + if ($timeline_icon !== null) { + $timeline_view = id(new PHUIIconView()) + ->setIcon( + $status->getTimelineIcon(), + $status->getTimelineColor()); + } else { + $timeline_view = null; + } + + if ($status->isClosedStatus()) { + $is_open = pht('Closed'); + } else { + $is_open = pht('Open'); + } + + $tag_color = $status->getTagColor(); + if ($tag_color !== null) { + $tag_view = id(new PHUIIconView()) + ->seticon('fa-tag', $tag_color); + } else { + $tag_view = null; + } + + $ansi_color = $status->getAnsiColor(); + if ($ansi_color !== null) { + $web_color = PHUIColor::getWebColorFromANSIColor($ansi_color); + $ansi_view = id(new PHUIIconView()) + ->setIcon('fa-stop', $web_color); + } else { + $ansi_view = null; + } + + + $rows[] = array( + $status->getKey(), + $status->getLegacyKey(), + $icon, + $timeline_view, + $tag_view, + $ansi_view, + $is_open, + $status->getDisplayName(), + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('Value'), + pht('Legacy Value'), + pht('Icon'), + pht('Timeline Icon'), + pht('Tag Color'), + pht('ANSI Color'), + pht('Open/Closed'), + pht('Name'), + )) + ->setColumnClasses( + array( + null, + null, + null, + null, + null, + null, + null, + 'wide pri', + )); + + $view = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Differential Revision Statuses')) + ->setTable($table); + + return $view; + } + + private function renderUnitStatuses(PhabricatorUser $viewer) { + $statuses = DifferentialUnitStatus::getStatusMap(); + + $rows = array(); + foreach ($statuses as $status) { + $rows[] = array( + $status->getValue(), + id(new PHUIIconView()) + ->setIcon($status->getIconIcon(), $status->getIconColor()), + $status->getName(), + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('Value'), + pht('Icon'), + pht('Name'), + )) + ->setColumnClasses( + array( + null, + null, + 'wide pri', + )); + + $view = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Differential Unit Statuses')) + ->setTable($table); + + return $view; + } + + private function renderLintStatuses(PhabricatorUser $viewer) { + $statuses = DifferentialLintStatus::getStatusMap(); + + $rows = array(); + foreach ($statuses as $status) { + $rows[] = array( + $status->getValue(), + id(new PHUIIconView()) + ->setIcon($status->getIconIcon(), $status->getIconColor()), + $status->getName(), + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('Value'), + pht('Icon'), + pht('Name'), + )) + ->setColumnClasses( + array( + null, + null, + 'wide pri', + )); + + $view = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Differential Lint Statuses')) + ->setTable($table); + + return $view; + } + + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/constants/DifferentialLintStatus.php phabricator-0~git20220903/phabricator/src/applications/differential/constants/DifferentialLintStatus.php --- phabricator-0~git20200925/phabricator/src/applications/differential/constants/DifferentialLintStatus.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/constants/DifferentialLintStatus.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,4 +9,85 @@ const LINT_SKIP = 4; const LINT_AUTO_SKIP = 6; + private $value; + + public static function newStatusFromValue($value) { + $status = new self(); + $status->value = $value; + return $status; + } + + public function getValue() { + return $this->value; + } + + public function getName() { + $name = $this->getLintStatusProperty('name'); + + if ($name === null) { + $name = pht('Unknown Lint Status ("%s")', $this->getValue()); + } + + return $name; + } + + public function getIconIcon() { + return $this->getLintStatusProperty('icon.icon'); + } + + public function getIconColor() { + return $this->getLintStatusProperty('icon.color'); + } + + public static function getStatusMap() { + $results = array(); + + foreach (self::newLintStatusMap() as $value => $ignored) { + $results[$value] = self::newStatusFromValue($value); + } + + return $results; + } + + private function getLintStatusProperty($key, $default = null) { + $map = self::newLintStatusMap(); + $properties = idx($map, $this->getValue(), array()); + return idx($properties, $key, $default); + } + + private static function newLintStatusMap() { + return array( + self::LINT_NONE => array( + 'name' => pht('No Lint Coverage'), + 'icon.icon' => 'fa-ban', + 'icon.color' => 'grey', + ), + self::LINT_OKAY => array( + 'name' => pht('Lint Passed'), + 'icon.icon' => 'fa-check', + 'icon.color' => 'green', + ), + self::LINT_WARN => array( + 'name' => pht('Lint Warnings'), + 'icon.icon' => 'fa-exclamation-triangle', + 'icon.color' => 'yellow', + ), + self::LINT_FAIL => array( + 'name' => pht('Lint Errors'), + 'icon.icon' => 'fa-times', + 'icon.color' => 'red', + ), + self::LINT_SKIP => array( + 'name' => pht('Lint Skipped'), + 'icon.icon' => 'fa-fast-forward', + 'icon.color' => 'blue', + ), + self::LINT_AUTO_SKIP => array( + 'name' => pht('Lint Not Applicable'), + 'icon.icon' => 'fa-code', + 'icon.color' => 'grey', + ), + ); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/constants/DifferentialUnitStatus.php phabricator-0~git20220903/phabricator/src/applications/differential/constants/DifferentialUnitStatus.php --- phabricator-0~git20200925/phabricator/src/applications/differential/constants/DifferentialUnitStatus.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/constants/DifferentialUnitStatus.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,4 +9,85 @@ const UNIT_SKIP = 4; const UNIT_AUTO_SKIP = 6; + private $value; + + public static function newStatusFromValue($value) { + $status = new self(); + $status->value = $value; + return $status; + } + + public function getValue() { + return $this->value; + } + + public function getName() { + $name = $this->getUnitStatusProperty('name'); + + if ($name === null) { + $name = pht('Unknown Unit Status ("%s")', $this->getValue()); + } + + return $name; + } + + public function getIconIcon() { + return $this->getUnitStatusProperty('icon.icon'); + } + + public function getIconColor() { + return $this->getUnitStatusProperty('icon.color'); + } + + public static function getStatusMap() { + $results = array(); + + foreach (self::newUnitStatusMap() as $value => $ignored) { + $results[$value] = self::newStatusFromValue($value); + } + + return $results; + } + + private function getUnitStatusProperty($key, $default = null) { + $map = self::newUnitStatusMap(); + $properties = idx($map, $this->getValue(), array()); + return idx($properties, $key, $default); + } + + private static function newUnitStatusMap() { + return array( + self::UNIT_NONE => array( + 'name' => pht('No Test Coverage'), + 'icon.icon' => 'fa-ban', + 'icon.color' => 'grey', + ), + self::UNIT_OKAY => array( + 'name' => pht('Tests Passed'), + 'icon.icon' => 'fa-check', + 'icon.color' => 'green', + ), + self::UNIT_WARN => array( + 'name' => pht('Test Warnings'), + 'icon.icon' => 'fa-exclamation-triangle', + 'icon.color' => 'yellow', + ), + self::UNIT_FAIL => array( + 'name' => pht('Test Failures'), + 'icon.icon' => 'fa-times', + 'icon.color' => 'red', + ), + self::UNIT_SKIP => array( + 'name' => pht('Tests Skipped'), + 'icon.icon' => 'fa-fast-forward', + 'icon.color' => 'blue', + ), + self::UNIT_AUTO_SKIP => array( + 'name' => pht('Tests Not Applicable'), + 'icon.icon' => 'fa-code', + 'icon.color' => 'grey', + ), + ); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/controller/DifferentialDiffCreateController.php phabricator-0~git20220903/phabricator/src/applications/differential/controller/DifferentialDiffCreateController.php --- phabricator-0~git20200925/phabricator/src/applications/differential/controller/DifferentialDiffCreateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/controller/DifferentialDiffCreateController.php 2022-06-14 16:29:55.000000000 +0000 @@ -27,7 +27,13 @@ $diff = null; // This object is just for policy stuff $diff_object = DifferentialDiff::initializeNewDiff($viewer); - $repository_phid = null; + + if ($revision) { + $repository_phid = $revision->getRepositoryPHID(); + } else { + $repository_phid = null; + } + $errors = array(); $e_diff = null; $e_file = null; @@ -106,8 +112,9 @@ array( array( pht( - 'The best way to create a diff is to use the Arcanist '. - 'command-line tool.'), + 'The best way to create a diff is to use the %s '. + 'command-line tool.', + PlatformSymbols::getPlatformClientName()), ' ', $arcanist_link, ), diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/controller/DifferentialRevisionAffectedPathsController.php phabricator-0~git20220903/phabricator/src/applications/differential/controller/DifferentialRevisionAffectedPathsController.php --- phabricator-0~git20200925/phabricator/src/applications/differential/controller/DifferentialRevisionAffectedPathsController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/controller/DifferentialRevisionAffectedPathsController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,127 @@ +<?php + +final class DifferentialRevisionAffectedPathsController + extends DifferentialController { + + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); + $id = $request->getURIData('id'); + + $revision = id(new DifferentialRevisionQuery()) + ->withIDs(array($id)) + ->setViewer($viewer) + ->executeOne(); + if (!$revision) { + return new Aphront404Response(); + } + + $table = new DifferentialAffectedPath(); + $conn = $table->establishConnection('r'); + + $paths = queryfx_all( + $conn, + 'SELECT * FROM %R WHERE revisionID = %d', + $table, + $revision->getID()); + + $repository_ids = array(); + $path_ids = array(); + + foreach ($paths as $path) { + $repository_id = $path['repositoryID']; + $path_id = $path['pathID']; + + $repository_ids[] = $repository_id; + $path_ids[] = $path_id; + } + + $repository_ids = array_fuse($repository_ids); + + if ($repository_ids) { + $repositories = id(new PhabricatorRepositoryQuery()) + ->setViewer($viewer) + ->withIDs($repository_ids) + ->execute(); + $repositories = mpull($repositories, null, 'getID'); + } else { + $repositories = array(); + } + + $handles = $viewer->loadHandles(mpull($repositories, 'getPHID')); + + $path_ids = array_fuse($path_ids); + if ($path_ids) { + $path_names = id(new DiffusionPathQuery()) + ->withPathIDs($path_ids) + ->execute(); + } else { + $path_names = array(); + } + + $rows = array(); + foreach ($paths as $path) { + $repository_id = $path['repositoryID']; + $path_id = $path['pathID']; + + $repository = idx($repositories, $repository_id); + if ($repository) { + $repository_phid = $repository->getPHID(); + $repository_link = $handles[$repository_phid]->renderLink(); + } else { + $repository_link = null; + } + + $path_name = idx($path_names, $path_id); + if ($path_name !== null) { + $path_view = $path_name['path']; + } else { + $path_view = null; + } + + $rows[] = array( + $repository_id, + $repository_link, + $path_id, + $path_view, + ); + } + + // Sort rows by path name. + $rows = isort($rows, 3); + + $table_view = id(new AphrontTableView($rows)) + ->setNoDataString(pht('This revision has no indexed affected paths.')) + ->setHeaders( + array( + pht('Repository ID'), + pht('Repository'), + pht('Path ID'), + pht('Path'), + )) + ->setColumnClasses( + array( + null, + null, + null, + 'wide', + )); + + $box_view = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Affected Path Index')) + ->setTable($table_view); + + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($revision->getMonogram(), $revision->getURI()) + ->addTextCrumb(pht('Affected Path Index')); + + return $this->newPage() + ->setCrumbs($crumbs) + ->setTitle( + array( + $revision->getMonogram(), + pht('Affected Path Index'), + )) + ->appendChild($box_view); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/controller/DifferentialRevisionViewController.php phabricator-0~git20220903/phabricator/src/applications/differential/controller/DifferentialRevisionViewController.php --- phabricator-0~git20200925/phabricator/src/applications/differential/controller/DifferentialRevisionViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/controller/DifferentialRevisionViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -510,6 +510,11 @@ ->setLoadEntireGraph(true) ->loadGraph(); if (!$stack_graph->isEmpty()) { + // See PHI1900. The graph UI element now tries to figure out the correct + // height automatically, but currently can't in this case because the + // element is not visible when the page loads. Set an explicit height. + $stack_graph->setHeight(34); + $stack_table = $stack_graph->newGraphTable(); $parent_type = DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST; @@ -981,6 +986,8 @@ PhabricatorRepository $repository) { assert_instances_of($changesets, 'DifferentialChangeset'); + $viewer = $this->getViewer(); + $paths = array(); foreach ($changesets as $changeset) { $paths[] = $changeset->getAbsoluteRepositoryPath( @@ -992,34 +999,30 @@ return array(); } - $path_map = id(new DiffusionPathIDQuery($paths))->loadPathIDs(); - - if (!$path_map) { - return array(); - } - $recent = (PhabricatorTime::getNow() - phutil_units('30 days in seconds')); $query = id(new DifferentialRevisionQuery()) - ->setViewer($this->getRequest()->getUser()) + ->setViewer($viewer) ->withIsOpen(true) ->withUpdatedEpochBetween($recent, null) ->setOrder(DifferentialRevisionQuery::ORDER_MODIFIED) ->setLimit(10) ->needFlags(true) ->needDrafts(true) - ->needReviewers(true); - - foreach ($path_map as $path => $path_id) { - $query->withPath($repository->getID(), $path_id); - } + ->needReviewers(true) + ->withRepositoryPHIDs( + array( + $repository->getPHID(), + )) + ->withPaths($paths); $results = $query->execute(); // Strip out *this* revision. foreach ($results as $key => $result) { if ($result->getID() == $this->revisionID) { - unset($results[$key]); + unset($results[$key]); + break; } } @@ -1279,7 +1282,7 @@ } private function buildUnitMessagesView( - $diff, + DifferentialDiff $diff, DifferentialRevision $revision) { $viewer = $this->getViewer(); @@ -1307,14 +1310,8 @@ return null; } - $excuse = null; - if ($diff->hasDiffProperty('arc:unit-excuse')) { - $excuse = $diff->getProperty('arc:unit-excuse'); - } - return id(new HarbormasterUnitSummaryView()) ->setViewer($viewer) - ->setExcuse($excuse) ->setBuildable($diff->getBuildable()) ->setUnitMessages($diff->getUnitMessages()) ->setLimit(5) diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialJIRAIssuesField.php phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialJIRAIssuesField.php --- phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialJIRAIssuesField.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialJIRAIssuesField.php 2022-06-14 16:29:55.000000000 +0000 @@ -166,8 +166,9 @@ pht('Not Linked'), pht( 'You can not add JIRA issues (%s) to this revision because your '. - 'Phabricator account is not linked to a JIRA account.', - implode(', ', $add)), + '%s account is not linked to a JIRA account.', + implode(', ', $add), + PlatformSymbols::getPlatformServerName()), $xaction); continue; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialLintField.php phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialLintField.php --- phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialLintField.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialLintField.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,7 +38,6 @@ protected function getDiffPropertyKeys() { return array( 'arc:lint', - 'arc:lint-excuse', ); } @@ -84,33 +83,18 @@ DifferentialDiff $diff, array $messages) { - $colors = array( - DifferentialLintStatus::LINT_NONE => 'grey', - DifferentialLintStatus::LINT_OKAY => 'green', - DifferentialLintStatus::LINT_WARN => 'yellow', - DifferentialLintStatus::LINT_FAIL => 'red', - DifferentialLintStatus::LINT_SKIP => 'blue', - DifferentialLintStatus::LINT_AUTO_SKIP => 'blue', - ); - $icon_color = idx($colors, $diff->getLintStatus(), 'grey'); - - $message = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); + $status_value = $diff->getLintStatus(); + $status = DifferentialLintStatus::newStatusFromValue($status_value); - $excuse = $diff->getProperty('arc:lint-excuse'); - if (strlen($excuse)) { - $excuse = array( - phutil_tag('strong', array(), pht('Excuse:')), - ' ', - phutil_escape_html_newlines($excuse), - ); - } + $status_icon = $status->getIconIcon(); + $status_color = $status->getIconColor(); + $status_name = $status->getName(); $status = id(new PHUIStatusListView()) ->addItem( id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color) - ->setTarget($message) - ->setNote($excuse)); + ->setIcon($status_icon, $status_color) + ->setTarget($status_name)); return $status; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialReviewersField.php phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialReviewersField.php --- phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialReviewersField.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialReviewersField.php 2022-06-14 16:29:55.000000000 +0000 @@ -72,22 +72,40 @@ return array(); } + $viewer = $this->getViewer(); + + PhabricatorPolicyFilterSet::loadHandleViewCapabilities( + $viewer, + $handles, + array($revision)); + $all_resigned = true; $all_disabled = true; $any_reviewers = false; + $all_exiled = true; foreach ($this->getValue() as $reviewer) { $reviewer_phid = $reviewer->getReviewerPHID(); + $handle = $handles[$reviewer_phid]; $any_reviewers = true; - if (!$handles[$reviewer_phid]->isDisabled()) { + if (!$handle->isDisabled()) { $all_disabled = false; } if (!$reviewer->isResigned()) { $all_resigned = false; } + + if (!$handle->hasCapabilities()) { + $all_exiled = false; + } else { + if ($handle->hasViewCapability($revision)) { + $all_exiled = false; + } + } + } $warnings = array(); @@ -101,6 +119,10 @@ } else if ($all_resigned) { $warnings[] = pht( 'This revision needs review, but all reviewers have resigned.'); + } else if ($all_exiled) { + $warnings[] = pht( + 'This revision needs review, but no reviewers have permission '. + 'to view it.'); } return $warnings; diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialUnitField.php phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialUnitField.php --- phabricator-0~git20200925/phabricator/src/applications/differential/customfield/DifferentialUnitField.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/customfield/DifferentialUnitField.php 2022-06-14 16:29:55.000000000 +0000 @@ -72,29 +72,20 @@ } public function renderDiffPropertyViewValue(DifferentialDiff $diff) { + $status_value = $diff->getUnitStatus(); + $status = DifferentialUnitStatus::newStatusFromValue($status_value); - $colors = array( - DifferentialUnitStatus::UNIT_NONE => 'grey', - DifferentialUnitStatus::UNIT_OKAY => 'green', - DifferentialUnitStatus::UNIT_WARN => 'yellow', - DifferentialUnitStatus::UNIT_FAIL => 'red', - DifferentialUnitStatus::UNIT_SKIP => 'blue', - DifferentialUnitStatus::UNIT_AUTO_SKIP => 'blue', - ); - $icon_color = idx($colors, $diff->getUnitStatus(), 'grey'); - - $message = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage( - $diff->getUnitStatus()); + $status_icon = $status->getIconIcon(); + $status_color = $status->getIconColor(); + $status_name = $status->getName(); $status = id(new PHUIStatusListView()) ->addItem( id(new PHUIStatusItemView()) - ->setIcon(PHUIStatusItemView::ICON_STAR, $icon_color) - ->setTarget($message)); + ->setIcon($status_icon, $status_color) + ->setTarget($status_name)); return $status; } - - } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/editor/DifferentialRevisionEditEngine.php phabricator-0~git20220903/phabricator/src/applications/differential/editor/DifferentialRevisionEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/differential/editor/DifferentialRevisionEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/editor/DifferentialRevisionEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -176,6 +176,32 @@ ->setConduitTypeDescription(pht('New revision title.')) ->setValue($object->getTitle()); + $author_field = id(new PhabricatorDatasourceEditField()) + ->setKey(DifferentialRevisionAuthorTransaction::EDITKEY) + ->setLabel(pht('Author')) + ->setDatasource(new PhabricatorPeopleDatasource()) + ->setTransactionType( + DifferentialRevisionAuthorTransaction::TRANSACTIONTYPE) + ->setDescription(pht('Foist this revision upon someone else.')) + ->setConduitDescription(pht('Foist this revision upon another user.')) + ->setConduitTypeDescription(pht('New author.')) + ->setSingleValue($object->getAuthorPHID()); + + // Don't show the "Author" field when creating a revision using the web + // workflow, since it adds more noise than signal to this workflow. + if ($this->getIsCreate()) { + $author_field->setIsHidden(true); + } + + // Only show the "Foist Upon" comment action to the current revision + // author. Other users can use "Edit Revision", it's just very unlikley + // that they're interested in this action. + if ($viewer->getPHID() === $object->getAuthorPHID()) { + $author_field->setCommentActionLabel(pht('Foist Upon')); + } + + $fields[] = $author_field; + $fields[] = id(new PhabricatorRemarkupEditField()) ->setKey(DifferentialRevisionSummaryTransaction::EDITKEY) ->setLabel(pht('Summary')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/editor/DifferentialTransactionEditor.php phabricator-0~git20220903/phabricator/src/applications/differential/editor/DifferentialTransactionEditor.php --- phabricator-0~git20200925/phabricator/src/applications/differential/editor/DifferentialTransactionEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/editor/DifferentialTransactionEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -198,7 +198,7 @@ ->setNewValue($want_downgrade); } - $is_commandeer = false; + $new_author_phid = null; switch ($xaction->getTransactionType()) { case DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE: if ($this->getIsCloseByCommit()) { @@ -239,12 +239,22 @@ break; case DifferentialRevisionCommandeerTransaction::TRANSACTIONTYPE: - $is_commandeer = true; + $new_author_phid = $actor_phid; break; + + case DifferentialRevisionAuthorTransaction::TRANSACTIONTYPE: + $new_author_phid = $xaction->getNewValue(); + break; + } - if ($is_commandeer) { - $results[] = $this->newCommandeerReviewerTransaction($object); + if ($new_author_phid) { + $swap_xaction = $this->newSwapReviewersTransaction( + $object, + $new_author_phid); + if ($swap_xaction) { + $results[] = $swap_xaction; + } } if (!$this->didExpandInlineState) { @@ -330,24 +340,60 @@ pht('Failed to load revision from transaction finalization.')); } + $active_diff = $new_revision->getActiveDiff(); + $new_diff_phid = $active_diff->getPHID(); + $object->attachReviewers($new_revision->getReviewers()); - $object->attachActiveDiff($new_revision->getActiveDiff()); + $object->attachActiveDiff($active_diff); $object->attachRepository($new_revision->getRepository()); + $has_new_diff = false; + $should_index_paths = false; + $should_index_hashes = false; + $need_changesets = false; + foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE: - $diff = $this->requireDiff($xaction->getNewValue(), true); + $need_changesets = true; + + $new_diff_phid = $xaction->getNewValue(); + $has_new_diff = true; - // Update these denormalized index tables when we attach a new - // diff to a revision. + $should_index_paths = true; + $should_index_hashes = true; + break; + case DifferentialRevisionRepositoryTransaction::TRANSACTIONTYPE: + // The "AffectedPath" table denormalizes the repository, so we + // want to update the index if the repository changes. + + $need_changesets = true; - $this->updateRevisionHashTable($object, $diff); - $this->updateAffectedPathTable($object, $diff); + $should_index_paths = true; break; } } + if ($need_changesets) { + $new_diff = $this->requireDiff($new_diff_phid, true); + + if ($should_index_paths) { + id(new DifferentialAffectedPathEngine()) + ->setRevision($object) + ->setDiff($new_diff) + ->updateAffectedPaths(); + } + + if ($should_index_hashes) { + $this->updateRevisionHashTable($object, $new_diff); + } + + if ($has_new_diff) { + $this->ownersDiff = $new_diff; + $this->ownersChangesets = $new_diff->getChangesets(); + } + } + $xactions = $this->updateReviewStatus($object, $xactions); $this->markReviewerComments($object, $xactions); @@ -1246,99 +1292,6 @@ } /** - * Update the table which links Differential revisions to paths they affect, - * so Diffusion can efficiently find pending revisions for a given file. - */ - private function updateAffectedPathTable( - DifferentialRevision $revision, - DifferentialDiff $diff) { - - $repository = $revision->getRepository(); - if (!$repository) { - // The repository where the code lives is untracked. - return; - } - - $path_prefix = null; - - $local_root = $diff->getSourceControlPath(); - if ($local_root) { - // We're in a working copy which supports subdirectory checkouts (e.g., - // SVN) so we need to figure out what prefix we should add to each path - // (e.g., trunk/projects/example/) to get the absolute path from the - // root of the repository. DVCS systems like Git and Mercurial are not - // affected. - - // Normalize both paths and check if the repository root is a prefix of - // the local root. If so, throw it away. Note that this correctly handles - // the case where the remote path is "/". - $local_root = id(new PhutilURI($local_root))->getPath(); - $local_root = rtrim($local_root, '/'); - - $repo_root = id(new PhutilURI($repository->getRemoteURI()))->getPath(); - $repo_root = rtrim($repo_root, '/'); - - if (!strncmp($repo_root, $local_root, strlen($repo_root))) { - $path_prefix = substr($local_root, strlen($repo_root)); - } - } - - $changesets = $diff->getChangesets(); - $paths = array(); - foreach ($changesets as $changeset) { - $paths[] = $path_prefix.'/'.$changeset->getFilename(); - } - - // If this change affected paths, save the changesets so we can apply - // Owners rules to them later. - if ($paths) { - $this->ownersDiff = $diff; - $this->ownersChangesets = $changesets; - } - - // Mark this as also touching all parent paths, so you can see all pending - // changes to any file within a directory. - $all_paths = array(); - foreach ($paths as $local) { - foreach (DiffusionPathIDQuery::expandPathToRoot($local) as $path) { - $all_paths[$path] = true; - } - } - $all_paths = array_keys($all_paths); - - $path_ids = - PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( - $all_paths); - - $table = new DifferentialAffectedPath(); - $conn_w = $table->establishConnection('w'); - - $sql = array(); - foreach ($path_ids as $path_id) { - $sql[] = qsprintf( - $conn_w, - '(%d, %d, %d, %d)', - $repository->getID(), - $path_id, - time(), - $revision->getID()); - } - - queryfx( - $conn_w, - 'DELETE FROM %T WHERE revisionID = %d', - $table->getTableName(), - $revision->getID()); - foreach (array_chunk($sql, 256) as $chunk) { - queryfx( - $conn_w, - 'INSERT INTO %T (repositoryID, pathID, epoch, revisionID) VALUES %LQ', - $table->getTableName(), - $chunk); - } - } - - /** * Update the table connecting revisions to DVCS local hashes, so we can * identify revisions by commit/tree hashes. */ @@ -1472,21 +1425,25 @@ return $this; } - private function newCommandeerReviewerTransaction( - DifferentialRevision $revision) { + private function newSwapReviewersTransaction( + DifferentialRevision $revision, + $new_author_phid) { - $actor_phid = $this->getActingAsPHID(); - $owner_phid = $revision->getAuthorPHID(); + $old_author_phid = $revision->getAuthorPHID(); - // If the user is commandeering, add the previous owner as a - // reviewer and remove the actor. + if ($old_author_phid === $new_author_phid) { + return; + } + + // If the revision is changing authorship, add the previous author as a + // reviewer and remove the new author. $edits = array( '-' => array( - $actor_phid, + $new_author_phid, ), '+' => array( - $owner_phid, + $old_author_phid, ), ); @@ -1503,6 +1460,7 @@ ->setNewValue($edits); } + public function getActiveDiff($object) { if ($this->getIsNewObject()) { return null; diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/engine/DifferentialAffectedPathEngine.php phabricator-0~git20220903/phabricator/src/applications/differential/engine/DifferentialAffectedPathEngine.php --- phabricator-0~git20200925/phabricator/src/applications/differential/engine/DifferentialAffectedPathEngine.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/engine/DifferentialAffectedPathEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,136 @@ +<?php + +final class DifferentialAffectedPathEngine + extends Phobject { + + private $revision; + private $diff; + + public function setRevision(DifferentialRevision $revision) { + $this->revision = $revision; + return $this; + } + + public function getRevision() { + return $this->revision; + } + + public function setDiff(DifferentialDiff $diff) { + $this->diff = $diff; + return $this; + } + + public function getDiff() { + return $this->diff; + } + + public function updateAffectedPaths() { + $revision = $this->getRevision(); + $diff = $this->getDiff(); + $repository = $revision->getRepository(); + + if ($repository) { + $repository_id = $repository->getID(); + } else { + $repository_id = null; + } + + $paths = $this->getAffectedPaths(); + + $path_ids = + PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( + $paths); + + $table = new DifferentialAffectedPath(); + $conn = $table->establishConnection('w'); + + $sql = array(); + foreach ($path_ids as $path_id) { + $sql[] = qsprintf( + $conn, + '(%nd, %d, %d)', + $repository_id, + $path_id, + $revision->getID()); + } + + queryfx( + $conn, + 'DELETE FROM %R WHERE revisionID = %d', + $table, + $revision->getID()); + if ($sql) { + foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { + queryfx( + $conn, + 'INSERT INTO %R (repositoryID, pathID, revisionID) VALUES %LQ', + $table, + $chunk); + } + } + } + + public function destroyAffectedPaths() { + $revision = $this->getRevision(); + + $table = new DifferentialAffectedPath(); + $conn = $table->establishConnection('w'); + + queryfx( + $conn, + 'DELETE FROM %R WHERE revisionID = %d', + $table, + $revision->getID()); + } + + public function getAffectedPaths() { + $revision = $this->getRevision(); + $diff = $this->getDiff(); + $repository = $revision->getRepository(); + + $path_prefix = null; + if ($repository) { + $local_root = $diff->getSourceControlPath(); + if ($local_root) { + // We're in a working copy which supports subdirectory checkouts (e.g., + // SVN) so we need to figure out what prefix we should add to each path + // (e.g., trunk/projects/example/) to get the absolute path from the + // root of the repository. DVCS systems like Git and Mercurial are not + // affected. + + // Normalize both paths and check if the repository root is a prefix of + // the local root. If so, throw it away. Note that this correctly + // handles the case where the remote path is "/". + $local_root = id(new PhutilURI($local_root))->getPath(); + $local_root = rtrim($local_root, '/'); + + $repo_root = id(new PhutilURI($repository->getRemoteURI()))->getPath(); + $repo_root = rtrim($repo_root, '/'); + + if (!strncmp($repo_root, $local_root, strlen($repo_root))) { + $path_prefix = substr($local_root, strlen($repo_root)); + } + } + } + + $changesets = $diff->getChangesets(); + + $paths = array(); + foreach ($changesets as $changeset) { + $paths[] = $path_prefix.'/'.$changeset->getFilename(); + } + + // Mark this as also touching all parent paths, so you can see all pending + // changes to any file within a directory. + $all_paths = array(); + foreach ($paths as $local) { + foreach (DiffusionPathIDQuery::expandPathToRoot($local) as $path) { + $all_paths[$path] = true; + } + } + $all_paths = array_keys($all_paths); + + return $all_paths; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/parser/DifferentialChangesetParser.php phabricator-0~git20220903/phabricator/src/applications/differential/parser/DifferentialChangesetParser.php --- phabricator-0~git20200925/phabricator/src/applications/differential/parser/DifferentialChangesetParser.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/parser/DifferentialChangesetParser.php 2022-06-14 16:29:55.000000000 +0000 @@ -1816,7 +1816,7 @@ $viewstate = $this->getViewState(); $engine_key = $viewstate->getDocumentEngineKey(); - if (strlen($engine_key)) { + if (phutil_nonempty_string($engine_key)) { if (isset($shared_engines[$engine_key])) { $document_engine = $shared_engines[$engine_key]; } else { diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/parser/DifferentialLineAdjustmentMap.php phabricator-0~git20220903/phabricator/src/applications/differential/parser/DifferentialLineAdjustmentMap.php --- phabricator-0~git20200925/phabricator/src/applications/differential/parser/DifferentialLineAdjustmentMap.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/parser/DifferentialLineAdjustmentMap.php 2022-06-14 16:29:55.000000000 +0000 @@ -78,7 +78,7 @@ // If we're tracing the first line and this block is collapsing, // compute the offset from the top of the block. if (!$is_end && $this->isInverse) { - $offset = 0; + $offset = 1; $cursor = $line - 1; while (isset($nmap[$cursor])) { $prev = $nmap[$cursor]; diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/phid/DifferentialChangesetPHIDType.php phabricator-0~git20220903/phabricator/src/applications/differential/phid/DifferentialChangesetPHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/differential/phid/DifferentialChangesetPHIDType.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/phid/DifferentialChangesetPHIDType.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,41 @@ +<?php + +final class DifferentialChangesetPHIDType extends PhabricatorPHIDType { + + const TYPECONST = 'DCNG'; + + public function getTypeName() { + return pht('Differential Changeset'); + } + + public function newObject() { + return new DifferentialChangeset(); + } + + public function getPHIDTypeApplicationClass() { + return 'PhabricatorDifferentialApplication'; + } + + protected function buildQueryForObjects( + PhabricatorObjectQuery $query, + array $phids) { + + return id(new DifferentialChangesetQuery()) + ->withPHIDs($phids); + } + + public function loadHandles( + PhabricatorHandleQuery $query, + array $handles, + array $objects) { + + foreach ($handles as $phid => $handle) { + $changeset = $objects[$phid]; + + $id = $changeset->getID(); + + $handle->setName(pht('Changeset %d', $id)); + } + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialChangesetQuery.php phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialChangesetQuery.php --- phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialChangesetQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialChangesetQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,6 +4,9 @@ extends PhabricatorCursorPagedPolicyAwareQuery { private $ids; + private $phids; + private $diffPHIDs; + private $diffs; private $needAttachToDiffs; @@ -14,12 +17,22 @@ return $this; } + public function withPHIDs(array $phids) { + $this->phids = $phids; + return $this; + } + public function withDiffs(array $diffs) { assert_instances_of($diffs, 'DifferentialDiff'); $this->diffs = $diffs; return $this; } + public function withDiffPHIDs(array $phids) { + $this->diffPHIDs = $phids; + return $this; + } + public function needAttachToDiffs($attach) { $this->needAttachToDiffs = $attach; return $this; @@ -45,10 +58,6 @@ return new DifferentialChangeset(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $changesets) { // First, attach all the diffs we already have. We can just do this // directly without worrying about querying for them. When we don't have @@ -134,6 +143,31 @@ $this->ids); } + if ($this->phids !== null) { + $where[] = qsprintf( + $conn, + 'phid IN (%Ls)', + $this->phids); + } + + if ($this->diffPHIDs !== null) { + $diff_ids = queryfx_all( + $conn, + 'SELECT id FROM %R WHERE phid IN (%Ls)', + new DifferentialDiff(), + $this->diffPHIDs); + $diff_ids = ipull($diff_ids, 'id', null); + + if (!$diff_ids) { + throw new PhabricatorEmptyQueryException(); + } + + $where[] = qsprintf( + $conn, + 'diffID IN (%Ld)', + $diff_ids); + } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialChangesetSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialChangesetSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialChangesetSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialChangesetSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,11 +38,23 @@ protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); + + if ($map['diffPHIDs']) { + $query->withDiffPHIDs($map['diffPHIDs']); + } + return $query; } protected function buildCustomSearchFields() { - return array(); + return array( + id(new PhabricatorPHIDsSearchField()) + ->setLabel(pht('Diffs')) + ->setKey('diffPHIDs') + ->setAliases(array('diff', 'diffs', 'diffPHID')) + ->setDescription( + pht('Find changesets attached to a particular diff.')), + ); } protected function getURI($path) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialDiffQuery.php phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialDiffQuery.php --- phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialDiffQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialDiffQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -57,10 +57,6 @@ return new DifferentialDiff(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $diffs) { $revision_ids = array_filter(mpull($diffs, 'getRevisionID')); diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialHunkQuery.php phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialHunkQuery.php --- phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialHunkQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialHunkQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,10 +34,6 @@ return new DifferentialHunk(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $hunks) { $changesets = mpull($this->changesets, null, 'getID'); foreach ($hunks as $key => $hunk) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialRevisionQuery.php phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialRevisionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialRevisionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialRevisionQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,8 +8,6 @@ final class DifferentialRevisionQuery extends PhabricatorCursorPagedPolicyAwareQuery { - private $pathIDs = array(); - private $authors = array(); private $draftAuthors = array(); private $ccs = array(); @@ -27,6 +25,7 @@ private $createdEpochMin; private $createdEpochMax; private $noReviewers; + private $paths; const ORDER_MODIFIED = 'order-modified'; const ORDER_CREATED = 'order-created'; @@ -43,22 +42,15 @@ /* -( Query Configuration )------------------------------------------------ */ - /** - * Filter results to revisions which affect a Diffusion path ID in a given - * repository. You can call this multiple times to select revisions for - * several paths. + * Find revisions affecting one or more items in a list of paths. * - * @param int Diffusion repository ID. - * @param int Diffusion path ID. + * @param list<string> List of file paths. * @return this * @task config */ - public function withPath($repository_id, $path_id) { - $this->pathIDs[] = array( - 'repositoryID' => $repository_id, - 'pathID' => $path_id, - ); + public function withPaths(array $paths) { + $this->paths = $paths; return $this; } @@ -568,12 +560,13 @@ */ private function buildJoinsClause(AphrontDatabaseConnection $conn) { $joins = array(); - if ($this->pathIDs) { + + if ($this->paths) { $path_table = new DifferentialAffectedPath(); $joins[] = qsprintf( $conn, - 'JOIN %T p ON p.revisionID = r.id', - $path_table->getTableName()); + 'JOIN %R paths ON paths.revisionID = r.id', + $path_table); } if ($this->commitHashes) { @@ -635,20 +628,46 @@ * @task internal */ protected function buildWhereClause(AphrontDatabaseConnection $conn) { + $viewer = $this->getViewer(); $where = array(); - if ($this->pathIDs) { - $path_clauses = array(); - $repo_info = igroup($this->pathIDs, 'repositoryID'); - foreach ($repo_info as $repository_id => $paths) { - $path_clauses[] = qsprintf( + if ($this->paths !== null) { + $paths = $this->paths; + + $path_map = id(new DiffusionPathIDQuery($paths)) + ->loadPathIDs(); + + if (!$path_map) { + // If none of the paths have entries in the PathID table, we can not + // possibly find any revisions affecting them. + throw new PhabricatorEmptyQueryException(); + } + + $where[] = qsprintf( + $conn, + 'paths.pathID IN (%Ld)', + array_fuse($path_map)); + + // If we have repository PHIDs, additionally constrain this query to + // try to help MySQL execute it efficiently. + if ($this->repositoryPHIDs !== null) { + $repositories = id(new PhabricatorRepositoryQuery()) + ->setViewer($viewer) + ->setParentQuery($this) + ->withPHIDs($this->repositoryPHIDs) + ->execute(); + + if (!$repositories) { + throw new PhabricatorEmptyQueryException(); + } + + $repository_ids = mpull($repositories, 'getID'); + + $where[] = qsprintf( $conn, - '(p.repositoryID = %d AND p.pathID IN (%Ld))', - $repository_id, - ipull($paths, 'pathID')); + 'paths.repositoryID IN (%Ld)', + $repository_ids); } - $path_clauses = qsprintf($conn, '%LO', $path_clauses); - $where[] = $path_clauses; } if ($this->authors) { @@ -778,7 +797,9 @@ */ protected function shouldGroupQueryResultRows() { - if (count($this->pathIDs) > 1) { + if ($this->paths) { + // (If we have exactly one repository and exactly one path, we don't + // technically need to group, but it's simpler to always group.) return true; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialRevisionSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialRevisionSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialRevisionSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialRevisionSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -57,6 +57,10 @@ $map['modifiedEnd']); } + if ($map['affectedPaths']) { + $query->withPaths($map['affectedPaths']); + } + return $query; } @@ -118,6 +122,12 @@ ->setIsHidden(true) ->setDescription( pht('Find revisions modified at or before a particular time.')), + id(new PhabricatorSearchStringListField()) + ->setKey('affectedPaths') + ->setLabel(pht('Affected Paths')) + ->setDescription( + pht('Search for revisions affecting particular paths.')) + ->setIsHidden(true), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialViewStateQuery.php phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialViewStateQuery.php --- phabricator-0~git20200925/phabricator/src/applications/differential/query/DifferentialViewStateQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/query/DifferentialViewStateQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new DifferentialViewState(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/render/DifferentialChangesetRenderer.php phabricator-0~git20220903/phabricator/src/applications/differential/render/DifferentialChangesetRenderer.php --- phabricator-0~git20200925/phabricator/src/applications/differential/render/DifferentialChangesetRenderer.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/render/DifferentialChangesetRenderer.php 2022-06-14 16:29:55.000000000 +0000 @@ -718,6 +718,9 @@ foreach ($views as $key => $view) { $scaffold = $this->getRowScaffoldForInline($view); + + $scaffold->setIsUndoTemplate(true); + $views[$key] = id(new PHUIDiffInlineCommentTableScaffold()) ->addRowScaffold($scaffold); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/render/DifferentialChangesetTestRenderer.php phabricator-0~git20220903/phabricator/src/applications/differential/render/DifferentialChangesetTestRenderer.php --- phabricator-0~git20200925/phabricator/src/applications/differential/render/DifferentialChangesetTestRenderer.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/render/DifferentialChangesetTestRenderer.php 2022-06-14 16:29:55.000000000 +0000 @@ -76,7 +76,7 @@ $any_new = true; } $num = nonempty($p['line'], '-'); - $render = $p['render']; + $render = (string)$p['render']; $htype = nonempty($p['htype'], '.'); // TODO: This should probably happen earlier, whenever we deal with diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialAffectedPath.php phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialAffectedPath.php --- phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialAffectedPath.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialAffectedPath.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,7 +8,6 @@ protected $repositoryID; protected $pathID; - protected $epoch; protected $revisionID; protected function getConfiguration() { @@ -16,15 +15,16 @@ self::CONFIG_TIMESTAMPS => false, self::CONFIG_COLUMN_SCHEMA => array( 'id' => null, + 'repositoryID' => 'id?', ), self::CONFIG_KEY_SCHEMA => array( 'PRIMARY' => null, - 'repositoryID' => array( - 'columns' => array('repositoryID', 'pathID', 'epoch'), - ), 'revisionID' => array( 'columns' => array('revisionID'), ), + 'key_path' => array( + 'columns' => array('pathID', 'repositoryID'), + ), ), ) + parent::getConfiguration(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialChangeset.php phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialChangeset.php --- phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialChangeset.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialChangeset.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,7 +4,8 @@ extends DifferentialDAO implements PhabricatorPolicyInterface, - PhabricatorDestructibleInterface { + PhabricatorDestructibleInterface, + PhabricatorConduitResultInterface { protected $diffID; protected $oldFile; @@ -45,6 +46,7 @@ protected function getConfiguration() { return array( + self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'metadata' => self::SERIALIZATION_JSON, 'oldProperties' => self::SERIALIZATION_JSON, @@ -75,6 +77,10 @@ ) + parent::getConfiguration(); } + public function getPHIDType() { + return DifferentialChangesetPHIDType::TYPECONST; + } + public function getAffectedLineCount() { return $this->getAddLines() + $this->getDelLines(); } @@ -730,5 +736,49 @@ $this->saveTransaction(); } +/* -( PhabricatorConduitResultInterface )---------------------------------- */ + + public function getFieldSpecificationsForConduit() { + return array( + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('diffPHID') + ->setType('phid') + ->setDescription(pht('The diff the changeset is attached to.')), + ); + } + + public function getFieldValuesForConduit() { + $diff = $this->getDiff(); + + $repository = null; + if ($diff) { + $revision = $diff->getRevision(); + if ($revision) { + $repository = $revision->getRepository(); + } + } + + $absolute_path = $this->getAbsoluteRepositoryPath($repository, $diff); + if (strlen($absolute_path)) { + $absolute_path = base64_encode($absolute_path); + } else { + $absolute_path = null; + } + + $display_path = $this->getDisplayFilename(); + + return array( + 'diffPHID' => $diff->getPHID(), + 'path' => array( + 'displayPath' => $display_path, + 'absolutePath.base64' => $absolute_path, + ), + ); + } + + public function getConduitSearchAttachments() { + return array(); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialDiff.php phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialDiff.php --- phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialDiff.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialDiff.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,7 +42,7 @@ private $unsavedChangesets = array(); private $changesets = self::ATTACHABLE; private $revision = self::ATTACHABLE; - private $properties = array(); + private $properties = self::ATTACHABLE; private $buildable = self::ATTACHABLE; private $unitMessages = self::ATTACHABLE; @@ -338,6 +338,9 @@ } public function attachProperty($key, $value) { + if (!is_array($this->properties)) { + $this->properties = array(); + } $this->properties[$key] = $value; return $this; } @@ -547,9 +550,9 @@ 'buildable.revision' => pht('The differential revision ID, if applicable.'), 'repository.callsign' => - pht('The callsign of the repository in Phabricator.'), + pht('The callsign of the repository.'), 'repository.phid' => - pht('The PHID of the repository in Phabricator.'), + pht('The PHID of the repository.'), 'repository.vcs' => pht('The version control system, either "svn", "hg" or "git".'), 'repository.uri' => diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialHunk.php phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialHunk.php --- phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialHunk.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialHunk.php 2022-06-14 16:29:55.000000000 +0000 @@ -203,7 +203,7 @@ return implode('', $this->makeContent($include)); } - final private function makeContent($include) { + private function makeContent($include) { $lines = $this->getSplitLines(); $results = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialRevision.php phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialRevision.php --- phabricator-0~git20200925/phabricator/src/applications/differential/storage/DifferentialRevision.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/storage/DifferentialRevision.php 2022-06-14 16:29:55.000000000 +0000 @@ -311,9 +311,17 @@ // which the actor may be able to use their authority over to gain the // ability to force-accept for other packages. This query doesn't apply // dominion rules yet, and we'll bypass those rules later on. + + // See T13657. We ignore "watcher" packages which don't grant their owners + // permission to force accept anything. + $authority_query = id(new PhabricatorOwnersPackageQuery()) ->setViewer($viewer) ->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE)) + ->withAuthorityModes( + array( + PhabricatorOwnersPackage::AUTHORITY_STRONG, + )) ->withAuthorityPHIDs(array($viewer->getPHID())) ->withControl($repository_phid, $paths); $authority_packages = $authority_query->execute(); @@ -1022,16 +1030,9 @@ $engine->destroyObject($diff); } - $conn_w = $this->establishConnection('w'); - - // we have to do paths a little differently as they do not have - // an id or phid column for delete() to act on - $dummy_path = new DifferentialAffectedPath(); - queryfx( - $conn_w, - 'DELETE FROM %T WHERE revisionID = %d', - $dummy_path->getTableName(), - $this->getID()); + id(new DifferentialAffectedPathEngine()) + ->setRevision($this) + ->destroyAffectedPaths(); $viewstate_query = id(new DifferentialViewStateQuery()) ->setViewer($viewer) diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/storage/__tests__/DifferentialAdjustmentMapTestCase.php phabricator-0~git20220903/phabricator/src/applications/differential/storage/__tests__/DifferentialAdjustmentMapTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/differential/storage/__tests__/DifferentialAdjustmentMapTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/storage/__tests__/DifferentialAdjustmentMapTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,7 @@ <?php -final class DifferentialAdjustmentMapTestCase extends PhutilTestCase { +final class DifferentialAdjustmentMapTestCase + extends PhabricatorTestCase { public function testBasicMaps() { $change_map = array( @@ -62,7 +63,6 @@ DifferentialLineAdjustmentMap::newFromHunks($hunks)->getMap()); } - public function testInverseMaps() { $change_map = array( 1 => array(1), @@ -221,6 +221,45 @@ $this->assertEqual(3, $map->getFinalOffset()); } + public function testUnchangedUpdate() { + $diff1 = $this->loadHunks('insert.diff'); + $diff2 = $this->loadHunks('insert.diff'); + + $map = DifferentialLineAdjustmentMap::newInverseMap( + DifferentialLineAdjustmentMap::newFromHunks($diff1)); + + $map->addMapToChain( + DifferentialLineAdjustmentMap::newFromHunks($diff2)); + + $actual = array(); + for ($ii = 1; $ii <= 16; $ii++) { + $actual[$ii] = array( + $map->mapLine($ii, false), + $map->mapLine($ii, true), + ); + } + + $expect = array( + 1 => array(array(false, false, 1), array(false, false, 1)), + 2 => array(array(false, false, 2), array(false, false, 2)), + 3 => array(array(false, false, 3), array(false, false, 3)), + 4 => array(array(false, false, 4), array(false, false, 4)), + 5 => array(array(false, false, 5), array(false, false, 5)), + 6 => array(array(false, false, 6), array(false, false, 6)), + 7 => array(array(false, false, 7), array(false, false, 7)), + 8 => array(array(false, false, 8), array(false, false, 8)), + 9 => array(array(false, false, 9), array(false, false, 9)), + 10 => array(array(false, false, 10), array(false, false, 13)), + 11 => array(array(false, 1, 10), array(false, false, 14)), + 12 => array(array(false, 2, 10), array(false, false, 14)), + 13 => array(array(false, 3, 10), array(false, false, 14)), + 14 => array(array(false, false, 14), array(false, false, 14)), + 15 => array(array(false, false, 15), array(false, false, 15)), + 16 => array(array(false, false, 16), array(false, false, 16)), + ); + + $this->assertEqual($expect, $actual); + } public function testChainMaps() { // This test simulates porting inlines forward across a rebase. @@ -258,9 +297,9 @@ 5 => array(array(false, false, 3), array(false, false, 3)), 6 => array(array(false, false, 4), array(false, false, 4)), 7 => array(array(false, false, 5), array(false, false, 8)), - 8 => array(array(false, 0, 5), array(false, false, 9)), - 9 => array(array(false, 1, 5), array(false, false, 9)), - 10 => array(array(false, 2, 5), array(false, false, 9)), + 8 => array(array(false, 1, 5), array(false, false, 9)), + 9 => array(array(false, 2, 5), array(false, false, 9)), + 10 => array(array(false, 3, 5), array(false, false, 9)), 11 => array(array(false, false, 9), array(false, false, 9)), 12 => array(array(false, false, 10), array(false, false, 10)), 13 => array(array(false, false, 11), array(false, false, 11)), diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/view/DifferentialChangesetDetailView.php phabricator-0~git20220903/phabricator/src/applications/differential/view/DifferentialChangesetDetailView.php --- phabricator-0~git20200925/phabricator/src/applications/differential/view/DifferentialChangesetDetailView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/view/DifferentialChangesetDetailView.php 2022-06-14 16:29:55.000000000 +0000 @@ -246,6 +246,7 @@ 'displayPath' => hsprintf('%s', $display_parts), 'icon' => $display_icon, 'pathParts' => $path_parts, + 'symbolPath' => $display_filename, 'pathIconIcon' => $changeset->getPathIconIcon(), 'pathIconColor' => $changeset->getPathIconColor(), diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/view/DifferentialReviewersView.php phabricator-0~git20220903/phabricator/src/applications/differential/view/DifferentialReviewersView.php --- phabricator-0~git20200925/phabricator/src/applications/differential/view/DifferentialReviewersView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/view/DifferentialReviewersView.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,6 +26,8 @@ public function render() { $viewer = $this->getUser(); $reviewers = $this->reviewers; + $diff = $this->diff; + $handles = $this->handles; $view = new PHUIStatusListView(); @@ -40,10 +42,15 @@ } } + PhabricatorPolicyFilterSet::loadHandleViewCapabilities( + $viewer, + $handles, + array($diff)); + $reviewers = $head + $tail; foreach ($reviewers as $reviewer) { $phid = $reviewer->getReviewerPHID(); - $handle = $this->handles[$phid]; + $handle = $handles[$phid]; $action_phid = $reviewer->getLastActionDiffPHID(); $is_current_action = $this->isCurrent($action_phid); @@ -154,7 +161,10 @@ } $item->setIcon($icon, $color, $label); - $item->setTarget($handle->renderHovercardLink()); + $item->setTarget( + $handle->renderHovercardLink( + null, + $diff->getPHID())); if ($reviewer->isPackage()) { if (!$reviewer->getChangesets()) { @@ -162,6 +172,15 @@ } } + if ($handle->hasCapabilities()) { + if (!$handle->hasViewCapability($diff)) { + $item + ->setIcon('fa-eye-slash', 'red') + ->setNote(pht('No View Permission')) + ->setIsExiled(true); + } + } + $view->addItem($item); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php phabricator-0~git20220903/phabricator/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php --- phabricator-0~git20200925/phabricator/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php 2022-06-14 16:29:55.000000000 +0000 @@ -139,29 +139,8 @@ } if ($diff) { - $unit_status = idx( - $this->unitStatus, - $diff->getPHID(), - $diff->getUnitStatus()); - - $lint = self::renderDiffLintStar($row['obj']); - $lint = phutil_tag( - 'div', - array( - 'class' => 'lintunit-star', - 'title' => self::getDiffLintMessage($diff), - ), - $lint); - - $unit = self::renderDiffUnitStar($unit_status); - $unit = phutil_tag( - 'div', - array( - 'class' => 'lintunit-star', - 'title' => self::getDiffUnitMessage($unit_status), - ), - $unit); - + $lint = $this->newLintStatusView($diff); + $unit = $this->newUnitStatusView($diff); $base = $this->renderBaseRevision($diff); } else { $lint = null; @@ -282,86 +261,6 @@ return $content; } - const STAR_NONE = 'none'; - const STAR_OKAY = 'okay'; - const STAR_WARN = 'warn'; - const STAR_FAIL = 'fail'; - const STAR_SKIP = 'skip'; - - private static function renderDiffLintStar(DifferentialDiff $diff) { - static $map = array( - DifferentialLintStatus::LINT_NONE => self::STAR_NONE, - DifferentialLintStatus::LINT_OKAY => self::STAR_OKAY, - DifferentialLintStatus::LINT_WARN => self::STAR_WARN, - DifferentialLintStatus::LINT_FAIL => self::STAR_FAIL, - DifferentialLintStatus::LINT_SKIP => self::STAR_SKIP, - DifferentialLintStatus::LINT_AUTO_SKIP => self::STAR_SKIP, - ); - - $star = idx($map, $diff->getLintStatus(), self::STAR_FAIL); - - return self::renderDiffStar($star); - } - - private static function renderDiffUnitStar($unit_status) { - static $map = array( - DifferentialUnitStatus::UNIT_NONE => self::STAR_NONE, - DifferentialUnitStatus::UNIT_OKAY => self::STAR_OKAY, - DifferentialUnitStatus::UNIT_WARN => self::STAR_WARN, - DifferentialUnitStatus::UNIT_FAIL => self::STAR_FAIL, - DifferentialUnitStatus::UNIT_SKIP => self::STAR_SKIP, - DifferentialUnitStatus::UNIT_AUTO_SKIP => self::STAR_SKIP, - ); - $star = idx($map, $unit_status, self::STAR_FAIL); - - return self::renderDiffStar($star); - } - - public static function getDiffLintMessage(DifferentialDiff $diff) { - switch ($diff->getLintStatus()) { - case DifferentialLintStatus::LINT_NONE: - return pht('No Linters Available'); - case DifferentialLintStatus::LINT_OKAY: - return pht('Lint OK'); - case DifferentialLintStatus::LINT_WARN: - return pht('Lint Warnings'); - case DifferentialLintStatus::LINT_FAIL: - return pht('Lint Errors'); - case DifferentialLintStatus::LINT_SKIP: - return pht('Lint Skipped'); - case DifferentialLintStatus::LINT_AUTO_SKIP: - return pht('Automatic diff as part of commit; lint not applicable.'); - } - return pht('Unknown'); - } - - public static function getDiffUnitMessage($unit_status) { - switch ($unit_status) { - case DifferentialUnitStatus::UNIT_NONE: - return pht('No Unit Test Coverage'); - case DifferentialUnitStatus::UNIT_OKAY: - return pht('Unit Tests OK'); - case DifferentialUnitStatus::UNIT_WARN: - return pht('Unit Test Warnings'); - case DifferentialUnitStatus::UNIT_FAIL: - return pht('Unit Test Errors'); - case DifferentialUnitStatus::UNIT_SKIP: - return pht('Unit Tests Skipped'); - case DifferentialUnitStatus::UNIT_AUTO_SKIP: - return pht( - 'Automatic diff as part of commit; unit tests not applicable.'); - } - return pht('Unknown'); - } - - private static function renderDiffStar($star) { - $class = 'diff-star-'.$star; - return phutil_tag( - 'span', - array('class' => $class), - "\xE2\x98\x85"); - } - private function renderBaseRevision(DifferentialDiff $diff) { switch ($diff->getSourceControlSystem()) { case 'git': @@ -401,4 +300,42 @@ } return $link; } + + private function newLintStatusView(DifferentialDiff $diff) { + $value = $diff->getLintStatus(); + $status = DifferentialLintStatus::newStatusFromValue($value); + + $icon = $status->getIconIcon(); + $color = $status->getIconColor(); + $name = $status->getName(); + + return $this->newDiffStatusIconView($icon, $color, $name); + } + + private function newUnitStatusView(DifferentialDiff $diff) { + $value = $diff->getUnitStatus(); + + // NOTE: We may be overriding the value on the diff with a value from + // Harbormaster. + $value = idx($this->unitStatus, $diff->getPHID(), $value); + + $status = DifferentialUnitStatus::newStatusFromValue($value); + + $icon = $status->getIconIcon(); + $color = $status->getIconColor(); + $name = $status->getName(); + + return $this->newDiffStatusIconView($icon, $color, $name); + } + + private function newDiffStatusIconView($icon, $color, $name) { + return id(new PHUIIconView()) + ->setIcon($icon, $color) + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => $name, + )); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/differential/xaction/DifferentialRevisionAuthorTransaction.php phabricator-0~git20220903/phabricator/src/applications/differential/xaction/DifferentialRevisionAuthorTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/differential/xaction/DifferentialRevisionAuthorTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/differential/xaction/DifferentialRevisionAuthorTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,165 @@ +<?php + +final class DifferentialRevisionAuthorTransaction + extends DifferentialRevisionTransactionType { + + const TRANSACTIONTYPE = 'differential.revision.author'; + const EDITKEY = 'author'; + + public function generateOldValue($object) { + return $object->getAuthorPHID(); + } + + public function generateNewValue($object, $value) { + return $value; + } + + public function applyInternalEffects($object, $value) { + $object->setAuthorPHID($value); + } + + public function validateTransactions($object, array $xactions) { + $actor = $this->getActor(); + $errors = array(); + + if (!$xactions) { + return $errors; + } + + foreach ($xactions as $xaction) { + $old = $xaction->generateOldValue($object); + $new = $xaction->getNewValue(); + + if ($old === $new) { + continue; + } + + if (!$new) { + $errors[] = $this->newInvalidError( + pht('Revisions must have an assigned author.'), + $xaction); + continue; + } + + $author_objects = id(new PhabricatorPeopleQuery()) + ->setViewer($actor) + ->withPHIDs(array($new)) + ->execute(); + if (!$author_objects) { + $errors[] = $this->newInvalidError( + pht('Author "%s" is not a valid user.', $new), + $xaction); + continue; + } + } + + return $errors; + } + + public function getIcon() { + $author_phid = $this->getAuthorPHID(); + $old_phid = $this->getOldValue(); + $new_phid = $this->getNewValue(); + + $is_commandeer = ($author_phid === $new_phid); + $is_foist = ($author_phid === $old_phid); + + if ($is_commandeer) { + return 'fa-flag'; + } + + if ($is_foist) { + return 'fa-gift'; + } + + return 'fa-user'; + } + + public function getColor() { + return 'sky'; + } + + public function getTitle() { + $author_phid = $this->getAuthorPHID(); + $old_phid = $this->getOldValue(); + $new_phid = $this->getNewValue(); + + $is_commandeer = ($author_phid === $new_phid); + $is_foist = ($author_phid === $old_phid); + + if ($is_commandeer) { + return pht( + '%s commandeered this revision from %s.', + $this->renderAuthor(), + $this->renderOldHandle()); + } + + if ($is_foist) { + if ($new_phid) { + return pht( + '%s foisted this revision upon %s.', + $this->renderAuthor(), + $this->renderNewHandle()); + } else { + + // This isn't a valid transaction that can be applied, but happens in + // the preview if you temporarily delete the tokenizer value. + + return pht( + '%s foisted this revision upon...', + $this->renderAuthor()); + } + } + + return pht( + '%s changed the author of this revision from %s to %s.', + $this->renderAuthor(), + $this->renderOldHandle(), + $this->renderNewHandle()); + } + + public function getTitleForFeed() { + $author_phid = $this->getAuthorPHID(); + $old_phid = $this->getOldValue(); + $new_phid = $this->getNewValue(); + + $is_commandeer = ($author_phid === $new_phid); + $is_foist = ($author_phid === $old_phid); + + if ($is_commandeer) { + return pht( + '%s commandeered %s from %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldHandle()); + } + + if ($is_foist) { + return pht( + '%s foisted %s upon %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewHandle()); + } + + return pht( + '%s changed the author of %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldHandle(), + $this->renderNewHandle()); + + } + + public function getTransactionTypeForConduit($xaction) { + return 'author'; + } + + public function getFieldValuesForConduit($object, $data) { + return array( + 'old' => $object->getOldValue(), + 'new' => $object->getNewValue(), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,22 +35,27 @@ protected function getGitResult(ConduitAPIRequest $request) { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); + $path = $request->getValue('path'); + if (!strlen($path) || $path === '/') { + $path = null; + } + $commit = $request->getValue('commit'); $offset = (int)$request->getValue('offset'); $limit = (int)$request->getValue('limit'); $result = $this->getEmptyResultSet(); - if ($path == '') { + if ($path === null) { // Fast path to improve the performance of the repository view; we know // the root is always a tree at any commit and always exists. - $stdout = 'tree'; + $path_type = 'tree'; } else { try { list($stdout) = $repository->execxLocalCommand( - 'cat-file -t %s:%s', - $commit, - $path); + 'cat-file -t -- %s', + sprintf('%s:%s', $commit, $path)); + $path_type = trim($stdout); } catch (CommandException $e) { // The "cat-file" command may fail if the path legitimately does not // exist, but it may also fail if the path is a submodule. This can @@ -62,7 +67,7 @@ list($sub_err, $sub_stdout) = $repository->execLocalCommand( 'ls-tree %s -- %s', - $commit, + gitsprintf('%s', $commit), $path); if (!$sub_err) { // If the path failed "cat-file" but "ls-tree" worked, we assume it @@ -86,8 +91,9 @@ if (preg_match('/^fatal: Not a valid object name/', $stderr)) { // Grab two logs, since the first one is when the object was deleted. list($stdout) = $repository->execxLocalCommand( - 'log -n2 --format="%%H" %s -- %s', - $commit, + 'log -n2 %s %s -- %s', + '--format=%H', + gitsprintf('%s', $commit), $path); $stdout = trim($stdout); if ($stdout) { @@ -109,7 +115,7 @@ } } - if (trim($stdout) == 'blob') { + if ($path_type === 'blob') { $result->setReasonForEmptyResultSet( DiffusionBrowseResultSet::REASON_IS_FILE); return $result; @@ -120,19 +126,25 @@ return $result; } - list($stdout) = $repository->execxLocalCommand( - 'ls-tree -z -l %s:%s', - $commit, - $path); - - $submodules = array(); - - if (strlen($path)) { - $prefix = rtrim($path, '/').'/'; + if ($path === null) { + list($stdout) = $repository->execxLocalCommand( + 'ls-tree -z -l %s --', + gitsprintf('%s', $commit)); } else { - $prefix = ''; + if ($path_type === 'tree') { + $path = rtrim($path, '/').'/'; + } else { + $path = rtrim($path, '/'); + } + + list($stdout) = $repository->execxLocalCommand( + 'ls-tree -z -l %s -- %s', + gitsprintf('%s', $commit), + $path); } + $submodules = array(); + $count = 0; $results = array(); $lines = empty($stdout) @@ -155,7 +167,7 @@ $line)); } - list($mode, $type, $hash, $size, $name) = $parts; + list($mode, $type, $hash, $size, $full_path) = $parts; $path_result = new DiffusionRepositoryPath(); @@ -173,8 +185,14 @@ } } - $path_result->setFullPath($prefix.$name); - $path_result->setPath($name); + if ($path === null) { + $local_path = $full_path; + } else { + $local_path = basename($full_path); + } + + $path_result->setFullPath($full_path); + $path_result->setPath($local_path); $path_result->setHash($hash); $path_result->setFileType($file_type); $path_result->setFileSize($size); @@ -207,15 +225,23 @@ // the wild. list($err, $contents) = $repository->execLocalCommand( - 'cat-file blob %s:.gitmodules', + 'cat-file blob -- %s:.gitmodules', $commit); if (!$err) { - $tmp = new TempFile(); - Filesystem::writeFile($tmp, $contents); - list($module_info) = $repository->execxLocalCommand( - 'config -l -f %s', - $tmp); + + // NOTE: After T13673, the user executing "git" may not be the same + // as the user this process is running as (usually the webserver user), + // so we can't reliably use a temporary file: the daemon user may not + // be able to use it. + + // Use "--file -" to read from stdin instead. If this fails in some + // older versions of Git, we could exempt this particular command from + // sudoing to the daemon user. + + $future = $repository->getLocalCommandFuture('config -l --file - --'); + $future->write($contents); + list($module_info) = $future->resolvex(); $dict = array(); $lines = explode("\n", trim($module_info)); @@ -225,11 +251,11 @@ $dict[$key] = $value; } - foreach ($submodules as $path) { - $full_path = $path->getFullPath(); + foreach ($submodules as $submodule_path) { + $full_path = $submodule_path->getFullPath(); $key = 'submodule.'.$full_path.'.url'; if (isset($dict[$key])) { - $path->setExternalURI($dict[$key]); + $submodule_path->setExternalURI($dict[$key]); } } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -25,7 +25,7 @@ $repository = $this->getDiffusionRequest()->getRepository(); $commit = $request->getValue('commit'); list($err, $merge_base) = $repository->execLocalCommand( - 'cat-file -t %s', + 'cat-file -t -- %s', $commit); return !$err; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -45,7 +45,12 @@ $repository = $drequest->getRepository(); $commit_hash = $request->getValue('commit'); $against_hash = $request->getValue('against'); + $path = $request->getValue('path'); + if (!strlen($path)) { + $path = null; + } + $offset = $request->getValue('offset'); $limit = $request->getValue('limit'); @@ -55,18 +60,27 @@ $commit_range = $commit_hash; } + $argv = array(); + + $argv[] = '--skip'; + $argv[] = $offset; + + $argv[] = '--max-count'; + $argv[] = $limit; + + $argv[] = '--format=%H:%P'; + + $argv[] = gitsprintf('%s', $commit_range); + + $argv[] = '--'; + + if ($path !== null) { + $argv[] = $path; + } + list($stdout) = $repository->execxLocalCommand( - 'log '. - '--skip=%d '. - '-n %d '. - '--pretty=format:%s '. - '%s -- %C', - $offset, - $limit, - '%H:%P', - $commit_range, - // Git omits merge commits if the path is provided, even if it is empty. - (strlen($path) ? csprintf('%s', $path) : '')); + 'log %Ls', + $argv); $lines = explode("\n", trim($stdout)); $lines = array_filter($lines); @@ -122,28 +136,33 @@ // stop history (this is more consistent with the Mercurial worldview of // branches). + $path_args = array(); if (strlen($path)) { - $path_arg = csprintf('%s', $path); + $path_args[] = $path; $revset_arg = hgsprintf( 'reverse(ancestors(%s))', $commit_hash); } else { - $path_arg = ''; $revset_arg = hgsprintf( 'reverse(ancestors(%s)) and branch(%s)', - $drequest->getBranch(), - $commit_hash); + $commit_hash, + $drequest->getBranch()); + } + + $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg'); + if ($hg_analyzer->isMercurialTemplatePnodeAvailable()) { + $hg_log_template = '{node} {p1.node} {p2.node}\\n'; + } else { + $hg_log_template = '{node} {p1node} {p2node}\\n'; } list($stdout) = $repository->execxLocalCommand( - 'log --debug --template %s --limit %d --rev %s -- %C', - '{node};{parents}\\n', + 'log --template %s --limit %d --rev %s -- %Ls', + $hg_log_template, ($offset + $limit), // No '--skip' in Mercurial. $revset_arg, - $path_arg); + $path_args); - $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( - $stdout); $lines = explode("\n", trim($stdout)); $lines = array_slice($lines, $offset); @@ -152,28 +171,19 @@ $last = null; foreach (array_reverse($lines) as $line) { - list($hash, $parents) = explode(';', $line); - $parents = trim($parents); - if (!$parents) { - if ($last === null) { - $parent_map[$hash] = array('...'); - } else { - $parent_map[$hash] = array($last); - } - } else { - $parents = preg_split('/\s+/', $parents); - foreach ($parents as $parent) { - list($plocal, $phash) = explode(':', $parent); - if (!preg_match('/^0+$/', $phash)) { - $parent_map[$hash][] = $phash; - } - } - // This may happen for the zeroth commit in repository, both hashes - // are "000000000...". - if (empty($parent_map[$hash])) { - $parent_map[$hash] = array('...'); + $parts = explode(' ', trim($line)); + $hash = $parts[0]; + $parents = array_slice($parts, 1, 2); + foreach ($parents as $parent) { + if (!preg_match('/^0+\z/', $parent)) { + $parent_map[$hash][] = $parent; } } + // This may happen for the zeroth commit in repository, both hashes + // are "000000000...". + if (empty($parent_map[$hash])) { + $parent_map[$hash] = array('...'); + } // The rendering code expects the first commit to be "mainline", like // Git. Flip the order so it does the right thing. diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -43,9 +43,9 @@ // it requires the commit to have a parent that we can diff against. The // first commit doesn't, so "commit^" is not a valid ref. list($parents) = $repository->execxLocalCommand( - 'log -n1 --format=%s %s', - '%P', - $commit); + 'log -n1 %s %s --', + '--format=%P', + gitsprintf('%s', $commit)); $use_log = !strlen(trim($parents)); // First, get a fast raw diff without "--find-copies-harder". This flag @@ -96,18 +96,18 @@ // NOTE: "--pretty=format: " is to disable diff output, we only want the // part we get from "--raw". $future = $repository->getLocalCommandFuture( - 'log %Ls --pretty=format: %s', + 'log %Ls --pretty=format: %s --', $flags, - $commit); + gitsprintf('%s', $commit)); } else { // Otherwise, we can use "diff", which will give us output for merges. // We diff against the first parent, as this is generally the expectation // and results in sensible behavior. $future = $repository->getLocalCommandFuture( - 'diff %Ls %s^1 %s', + 'diff %Ls %s %s --', $flags, - $commit, - $commit); + gitsprintf('%s^1', $commit), + gitsprintf('%s', $commit)); } // Don't spend more than 30 seconds generating the slower output. diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -33,8 +33,9 @@ continue; } list($hash) = $repository->execxLocalCommand( - 'log -n1 --format=%%H %s -- %s', - $commit, + 'log -n1 %s %s -- %s', + '--format=%H', + gitsprintf('%s', $commit), $path); $results[$path] = trim($hash); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionLookSoonConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,7 +13,7 @@ public function getMethodDescription() { return pht( - 'Advises Phabricator to look for new commits in a repository as soon '. + 'Advises this server to look for new commits in a repository as soon '. 'as possible. This advice is most useful if you have just pushed new '. 'commits to that repository.'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionMergedCommitsQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,9 +35,9 @@ $limit = $this->getLimit($request); list($parents) = $repository->execxLocalCommand( - 'log -n 1 --format=%s %s', - '%P', - $commit); + 'log -n 1 %s %s --', + '--format=%P', + gitsprintf('%s', $commit)); $parents = preg_split('/\s+/', trim($parents)); if (count($parents) < 2) { @@ -50,12 +50,12 @@ $first_parent = head($parents); list($logs) = $repository->execxLocalCommand( - 'log -n %d --format=%s %s %s --', + 'log -n %d %s %s %s --', // NOTE: "+ 1" accounts for the merge commit itself. $limit + 1, - '%H', - $commit, - '^'.$first_parent); + '--format=%H', + gitsprintf('%s', $commit), + gitsprintf('%s', '^'.$first_parent)); $hashes = explode("\n", trim($logs)); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionQueryPathsConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -45,7 +45,7 @@ $future = $repository->getLocalCommandFuture( 'ls-tree --name-only -r -z %s -- %s', - $commit, + gitsprintf('%s', $commit), $path); $lines = id(new LinesOfALargeExecFuture($future))->setDelimiter("\0"); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionRefsQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -28,9 +28,9 @@ $commit = $request->getValue('commit'); list($stdout) = $repository->execxLocalCommand( - 'log --format=%s -n 1 %s --', - '%d', - $commit); + 'log -n 1 %s %s --', + '--format=%d', + gitsprintf('%s', $commit)); // %d, gives a weird output format // similar to (remote/one, remote/two, remote/three) diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/conduit/DiffusionSearchQueryConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -64,7 +64,7 @@ $future = $repository->getLocalCommandFuture( // NOTE: --perl-regexp is available only with libpcre compiled in. 'grep --extended-regexp --null -n --no-color -f - %s -- %s', - $drequest->getStableCommit(), + gitsprintf('%s', $drequest->getStableCommit()), $path); // NOTE: We're writing the pattern on stdin to avoid issues with UTF8 diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -61,16 +61,22 @@ ->setDescription(pht('Hard byte limit on including patches in email.')), $this->newOption('metamta.diffusion.time-limit', 'int', 60) ->setDescription(pht('Hard time limit on generating patches.')), + $this->newOption( 'audit.can-author-close-audit', 'bool', false) ->setBoolOptions( array( - pht('Enable Closing Audits'), - pht('Disable Closing Audits'), + pht('Enable Self-Accept'), + pht('Disable Self-Accept'), )) - ->setDescription(pht('Controls whether Author can Close Audits.')), + ->setDescription( + pht( + 'Allows the author of a commit to be an auditor and accept their '. + 'own commits. Note that this behavior is different from the '. + 'behavior implied by the name of the option: long ago, it did '. + 'something else.')), $this->newOption('bugtraq.url', 'string', null) ->addExample('https://bugs.php.net/%BUGID%', pht('PHP bugs')) @@ -101,12 +107,12 @@ ->setSummary(pht('Enable HTTP Basic Auth for repositories.')) ->setDescription( pht( - "Phabricator can serve repositories over HTTP, using HTTP basic ". + "This server can serve repositories over HTTP, using HTTP basic ". "auth.\n\n". "Because HTTP basic auth is less secure than SSH auth, it is ". "disabled by default. You can enable it here if you'd like to use ". "it anyway. There's nothing fundamentally insecure about it as ". - "long as Phabricator uses HTTPS, but it presents a much lower ". + "long as this server uses HTTPS, but it presents a much lower ". "barrier to attackers than SSH does.\n\n". "Consider using SSH for authenticated access to repositories ". "instead of HTTP.")), @@ -120,9 +126,9 @@ ->setSummary(pht('Allow Git Large File Storage (LFS).')) ->setDescription( pht( - 'Phabricator supports Git LFS, a Git extension for storing large '. + 'This server supports Git LFS, a Git extension for storing large '. 'files alongside a repository. Activate this setting to allow '. - 'the extension to store file data in Phabricator.')), + 'the extension to store file data.')), $this->newOption('diffusion.ssh-user', 'string', null) ->setLocked(true) ->setSummary(pht('Login username for SSH connections to repositories.')) @@ -144,10 +150,9 @@ ->setSummary(pht('Host for SSH connections to repositories.')) ->setDescription( pht( - 'If you accept Phabricator SSH traffic on a different host '. - 'from web traffic (for example, if you use different SSH and '. - 'web load balancers), you can set the SSH hostname here. This '. - 'is an advanced option.')), + 'If you accept SSH traffic on a different host from web traffic '. + '(for example, if you use different SSH and web load balancers), '. + 'you can set the SSH hostname here. This is an advanced option.')), $this->newOption('diffusion.fields', $custom_field_type, $default_fields) ->setCustomData( id(new PhabricatorRepositoryCommit()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionBrowseController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionBrowseController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionBrowseController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionBrowseController.php 2022-06-14 16:29:55.000000000 +0000 @@ -298,22 +298,8 @@ $empty_result->setDiffusionBrowseResultSet($results); $empty_result->setView($request->getStr('view')); } else { - $phids = array(); - foreach ($results->getPaths() as $result) { - $data = $result->getLastCommitData(); - if ($data) { - if ($data->getCommitDetail('authorPHID')) { - $phids[$data->getCommitDetail('authorPHID')] = true; - } - } - } - - $phids = array_keys($phids); - $handles = $this->loadViewerHandles($phids); - $browse_table = id(new DiffusionBrowseTableView()) ->setDiffusionRequest($drequest) - ->setHandles($handles) ->setPaths($results->getPaths()) ->setUser($request->getUser()); @@ -938,17 +924,12 @@ $repository = $drequest->getRepository(); $path = $drequest->getPath(); - $path_map = id(new DiffusionPathIDQuery(array($path)))->loadPathIDs(); - $path_id = idx($path_map, $path); - if (!$path_id) { - return null; - } - $recent = (PhabricatorTime::getNow() - phutil_units('30 days in seconds')); $revisions = id(new DifferentialRevisionQuery()) ->setViewer($viewer) - ->withPath($repository->getID(), $path_id) + ->withPaths(array($path)) + ->withRepositoryPHIDs(array($repository->getPHID())) ->withIsOpen(true) ->withUpdatedEpochBetween($recent, null) ->setOrder(DifferentialRevisionQuery::ORDER_MODIFIED) @@ -963,7 +944,7 @@ } $header = id(new PHUIHeaderView()) - ->setHeader(pht('Recently Open Revisions')); + ->setHeader(pht('Recent Open Revisions')); $list = id(new DifferentialRevisionListView()) ->setViewer($viewer) diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionCommitController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionCommitController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionCommitController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionCommitController.php 2022-06-14 16:29:55.000000000 +0000 @@ -598,10 +598,6 @@ $other_requests = array(); foreach ($audit_requests as $audit_request) { - if (!$audit_request->isInteresting()) { - continue; - } - if ($audit_request->isUser()) { $user_requests[] = $audit_request; } else { @@ -902,12 +898,13 @@ $view = new PHUIStatusListView(); foreach ($audit_requests as $request) { - $code = $request->getAuditStatus(); + $status = $request->getAuditRequestStatusObject(); + $item = new PHUIStatusItemView(); $item->setIcon( - PhabricatorAuditStatusConstants::getStatusIcon($code), - PhabricatorAuditStatusConstants::getStatusColor($code), - PhabricatorAuditStatusConstants::getStatusName($code)); + $status->getIconIcon(), + $status->getIconColor(), + $status->getStatusName()); $auditor_phid = $request->getAuditorPHID(); $target = $viewer->renderHandle($auditor_phid); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryController.php 2022-06-14 16:29:55.000000000 +0000 @@ -2,7 +2,6 @@ final class DiffusionRepositoryController extends DiffusionController { - private $historyFuture; private $browseFuture; private $branchButton = null; private $branchFuture; @@ -191,15 +190,6 @@ $path = $drequest->getPath(); $futures = array(); - $this->historyFuture = $this->callConduitMethod( - 'diffusion.historyquery', - array( - 'commit' => $commit, - 'path' => $path, - 'offset' => 0, - 'limit' => 15, - )); - $futures[] = $this->historyFuture; $browse_pager = id(new PHUIPagerView()) ->readFromRequest($request); @@ -230,33 +220,9 @@ // Just resolve all the futures before continuing. } - $phids = array(); $content = array(); try { - $history_results = $this->historyFuture->resolve(); - $history = DiffusionPathChange::newFromConduit( - $history_results['pathChanges']); - - foreach ($history as $item) { - $data = $item->getCommitData(); - if ($data) { - if ($data->getCommitDetail('authorPHID')) { - $phids[$data->getCommitDetail('authorPHID')] = true; - } - if ($data->getCommitDetail('committerPHID')) { - $phids[$data->getCommitDetail('committerPHID')] = true; - } - } - } - $history_exception = null; - } catch (Exception $ex) { - $history_results = null; - $history = null; - $history_exception = $ex; - } - - try { $browse_results = $this->browseFuture->resolve(); $browse_results = DiffusionBrowseResultSet::newFromConduit( $browse_results); @@ -264,18 +230,6 @@ $browse_paths = $browse_results->getPaths(); $browse_paths = $browse_pager->sliceResults($browse_paths); - foreach ($browse_paths as $item) { - $data = $item->getLastCommitData(); - if ($data) { - if ($data->getCommitDetail('authorPHID')) { - $phids[$data->getCommitDetail('authorPHID')] = true; - } - if ($data->getCommitDetail('committerPHID')) { - $phids[$data->getCommitDetail('committerPHID')] = true; - } - } - } - $browse_exception = null; } catch (Exception $ex) { $browse_results = null; @@ -283,9 +237,6 @@ $browse_exception = $ex; } - $phids = array_keys($phids); - $handles = $this->loadViewerHandles($phids); - if ($browse_results) { $readme = $this->renderDirectoryReadme($browse_results); } else { @@ -296,7 +247,6 @@ $browse_results, $browse_paths, $browse_exception, - $handles, $browse_pager); if ($readme) { @@ -524,7 +474,6 @@ $browse_results, $browse_paths, $browse_exception, - array $handles, PHUIPagerView $pager) { require_celerity_resource('diffusion-icons-css'); @@ -547,8 +496,7 @@ $browse_table = id(new DiffusionBrowseTableView()) ->setUser($viewer) - ->setDiffusionRequest($drequest) - ->setHandles($handles); + ->setDiffusionRequest($drequest); if ($browse_paths) { $browse_table->setPaths($browse_paths); } else { diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php 2022-06-14 16:29:55.000000000 +0000 @@ -23,7 +23,7 @@ ->appendParagraph( pht( 'This repository can not be protected from dangerous changes '. - 'because Phabricator does not control what users are allowed '. + 'because this server does not control what users are allowed '. 'to push to it.')) ->addCancelButton($panel_uri); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditEnormousController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditEnormousController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditEnormousController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditEnormousController.php 2022-06-14 16:29:55.000000000 +0000 @@ -23,7 +23,7 @@ ->appendParagraph( pht( 'This repository can not be protected from enormous changes '. - 'because Phabricator does not control what users are allowed '. + 'because this server does not control what users are allowed '. 'to push to it.')) ->addCancelButton($panel_uri); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php 2022-06-14 16:29:55.000000000 +0000 @@ -45,7 +45,7 @@ ->setTitle(pht('Update Repository Now')) ->appendParagraph( pht( - 'Normally, Phabricator automatically updates repositories '. + 'Normally, repositories are automatically updated '. 'based on how much time has elapsed since the last commit. '. 'This helps reduce load if you have a large number of mostly '. 'inactive repositories, which is common.')) @@ -57,7 +57,7 @@ 'repository.')) ->appendParagraph( pht( - 'To learn more about how Phabricator updates repositories, '. + 'To learn more about how repositories are updated, '. 'read %s in the documentation.', $doc_link)) ->addCancelButton($panel_uri) diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,10 @@ ->setTitle(pht('Builtin URIs Do Not Use Credentials')) ->appendParagraph( pht( - 'You can not set a credential for builtin URIs which Phabricator '. - 'hosts and serves. Phabricator does not fetch from these URIs or '. - 'push to these URIs, and does not need credentials to '. - 'authenticate any activity against them.')) + 'You can not set a credential for builtin URIs which this '. + 'server hosts. These URIs are not fetched from or pushed to, '. + 'and credentials are not required to authenticate any '. + 'activity against them.')) ->addCancelButton($view_uri); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionServeController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionServeController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionServeController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionServeController.php 2022-06-14 16:29:55.000000000 +0000 @@ -214,6 +214,11 @@ $viewer = new PhabricatorUser(); } + // See T13590. Some pathways, like error handling, may require unusual + // access to things like timezone information. These are fine to build + // inline; this pathway is not lightweight anyway. + $viewer->setAllowInlineCacheGeneration(true); + $this->setServiceViewer($viewer); $allow_public = PhabricatorEnv::getEnvConfig('policy.allow-public'); @@ -392,13 +397,31 @@ switch ($vcs_type) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $result = $this->serveVCSRequest($repository, $viewer); + $caught = null; + try { + $result = $this->serveVCSRequest($repository, $viewer); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + if ($caught) { + // We never expect an uncaught exception here, so dump it to the + // log. All routine errors should have been converted into Response + // objects by a lower layer. + phlog($caught); + + $result = new PhabricatorVCSResponse( + 500, + phutil_string_cast($caught->getMessage())); + } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $result = new PhabricatorVCSResponse( 500, pht( - 'Phabricator does not support HTTP access to Subversion '. + 'This server does not support HTTP access to Subversion '. 'repositories.')); break; default: @@ -922,18 +945,26 @@ // This is a pretty funky fix: it would be nice to more precisely detect // that a request is a `--depth N` clone request, but we don't have any code // to decode protocol frames yet. Instead, look for reasonable evidence - // in the error and output that we're looking at a `--depth` clone. + // in the output that we're looking at a `--depth` clone. - // For evidence this isn't completely crazy, see: - // https://github.com/schacon/grack/pull/7 + // A valid x-git-upload-pack-result response during packfile negotiation + // should end with a flush packet ("0000"). As long as that packet + // terminates the response body in the response, we'll assume the response + // is correct and complete. + + // See https://git-scm.com/docs/pack-protocol#_packfile_negotiation $stdout_regexp = '(^Content-Type: application/x-git-upload-pack-result)m'; - $stderr_regexp = '(The remote end hung up unexpectedly)'; $has_pack = preg_match($stdout_regexp, $stdout); - $is_hangup = preg_match($stderr_regexp, $stderr); - return $has_pack && $is_hangup; + if (strlen($stdout) >= 4) { + $has_flush_packet = (substr($stdout, -4) === "0000"); + } else { + $has_flush_packet = false; + } + + return ($has_pack && $has_flush_packet); } private function getCommonEnvironment(PhabricatorUser $viewer) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionSymbolController.php phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionSymbolController.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/controller/DiffusionSymbolController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/controller/DiffusionSymbolController.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,7 +4,10 @@ public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); + + // See T13638 for discussion of escaping. $name = $request->getURIData('name'); + $name = phutil_unescape_uri_path_component($name); $query = id(new DiffusionSymbolQuery()) ->setViewer($viewer) diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php phabricator-0~git20220903/phabricator/src/applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php 2022-06-14 16:29:55.000000000 +0000 @@ -98,9 +98,9 @@ } switch ($status) { - case PhabricatorAuditStatusConstants::AUDIT_REQUIRED: - case PhabricatorAuditStatusConstants::AUDIT_REQUESTED: - case PhabricatorAuditStatusConstants::CONCERNED: + case PhabricatorAuditRequestStatus::AUDIT_REQUIRED: + case PhabricatorAuditRequestStatus::AUDIT_REQUESTED: + case PhabricatorAuditRequestStatus::CONCERNED: $active += array_fuse($request_phids); break; default: diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php phabricator-0~git20220903/phabricator/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -217,7 +217,7 @@ $permanent_value = $object->getPermanentRefRules(); $automation_instructions = pht( - "Configure **Repository Automation** to allow Phabricator to ". + "Configure **Repository Automation** to allow this server to ". "write to this repository.". "\n\n". "IMPORTANT: This feature is new, experimental, and not supported. ". @@ -234,7 +234,7 @@ $subpath_instructions = pht( 'If you want to import only part of a repository, like `trunk/`, '. - 'you can set a path in **Import Only**. Phabricator will ignore '. + 'you can set a path in **Import Only**. The import process will ignore '. 'commits which do not affect this path.'); $filesize_warning = null; @@ -256,7 +256,7 @@ $track_instructions = pht( 'WARNING: The "Track Only" feature is deprecated. Use "Fetch Refs" '. 'and "Permanent Refs" instead. This feature will be removed in a '. - 'future version of Phabricator.'); + 'future version of this software.'); return array( id(new PhabricatorSelectEditField()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/engine/DiffusionCommitHookEngine.php phabricator-0~git20220903/phabricator/src/applications/diffusion/engine/DiffusionCommitHookEngine.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/engine/DiffusionCommitHookEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/engine/DiffusionCommitHookEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -216,13 +216,7 @@ $event->setRejectCode($this->rejectCode); $event->setRejectDetails($this->rejectDetails); - $event->openTransaction(); - $event->save(); - foreach ($all_updates as $update) { - $update->setPushEventPHID($event->getPHID()); - $update->save(); - } - $event->saveTransaction(); + $event->saveWithLogs($all_updates); if ($caught) { throw $caught; @@ -608,9 +602,9 @@ // repository. Particularly, this will cover the cases of a new branch, a // completely moved tag, etc. $futures[$key] = $this->getRepository()->getLocalCommandFuture( - 'log --format=%s %s --not --all', - '%H', - $ref_update->getRefNew()); + 'log %s %s --not --all --', + '--format=%H', + gitsprintf('%s', $ref_update->getRefNew())); } $content_updates = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/engineextension/DiffusionAuditorsSearchEngineAttachment.php phabricator-0~git20220903/phabricator/src/applications/diffusion/engineextension/DiffusionAuditorsSearchEngineAttachment.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/engineextension/DiffusionAuditorsSearchEngineAttachment.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/engineextension/DiffusionAuditorsSearchEngineAttachment.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,36 @@ +<?php + +final class DiffusionAuditorsSearchEngineAttachment + extends PhabricatorSearchEngineAttachment { + + public function getAttachmentName() { + return pht('Diffusion Auditors'); + } + + public function getAttachmentDescription() { + return pht('Get the auditors for each commit.'); + } + + public function willLoadAttachmentData($query, $spec) { + $query->needAuditRequests(true); + } + + public function getAttachmentForObject($object, $data, $spec) { + $auditors = $object->getAudits(); + + $list = array(); + foreach ($auditors as $auditor) { + $status = $auditor->getAuditRequestStatusObject(); + + $list[] = array( + 'auditorPHID' => $auditor->getAuditorPHID(), + 'status' => $status->getStatusValueForConduit(), + ); + } + + return array( + 'auditors' => $list, + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/engineextension/DiffusionDatasourceEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/diffusion/engineextension/DiffusionDatasourceEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/engineextension/DiffusionDatasourceEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/engineextension/DiffusionDatasourceEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -66,12 +66,12 @@ $parts = null; if (preg_match('/(.*)(?:\\.|::|->)(.*)/', $symbol, $parts)) { return urisprintf( - '/diffusion/symbol/%s/?jump=true&context=%s', + '/diffusion/symbol/%p/?jump=true&context=%s', $parts[2], $parts[1]); } else { return urisprintf( - '/diffusion/symbol/%s/?jump=true', + '/diffusion/symbol/%p/?jump=true', $symbol); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -48,7 +48,20 @@ $handles = $viewer->loadHandles($phids); $hovercard->setTitle($handle->getName()); - $hovercard->setDetail($commit->getSummary()); + + // See T13620. Use a longer slice of the message than the "summary" here, + // since we have at least a few lines of room in the UI. + $commit_message = $commit->getCommitMessageForDisplay(); + + $message_limit = 512; + + $short_message = id(new PhutilUTF8StringTruncator()) + ->setMaximumBytes($message_limit * 4) + ->setMaximumGlyphs($message_limit) + ->truncateString($commit_message); + $short_message = phutil_escape_html_newlines($short_message); + + $hovercard->setDetail($short_message); $repository = $handles[$repository_phid]->renderLink(); $hovercard->addField(pht('Repository'), $repository); @@ -64,7 +77,7 @@ } $date = phabricator_date($commit->getEpoch(), $viewer); - $hovercard->addField(pht('Date'), $date); + $hovercard->addField(pht('Commit Date'), $date); if (!$commit->isAuditStatusNoAudit()) { $status = $commit->getAuditStatusObject(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/herald/DiffusionAuditorsHeraldAction.php phabricator-0~git20220903/phabricator/src/applications/diffusion/herald/DiffusionAuditorsHeraldAction.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/herald/DiffusionAuditorsHeraldAction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/herald/DiffusionAuditorsHeraldAction.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,9 +38,7 @@ $current = array(); foreach ($auditors as $auditor) { - if ($auditor->isInteresting()) { - $current[] = $auditor->getAuditorPHID(); - } + $current[] = $auditor->getAuditorPHID(); } $allowed_types = array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php phabricator-0~git20220903/phabricator/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,9 +22,11 @@ $phids = array(); foreach ($audits as $audit) { - if ($audit->isActiveAudit()) { - $phids[] = $audit->getAuditorPHID(); + if ($audit->isResigned()) { + continue; } + + $phids[] = $audit->getAuditorPHID(); } return $phids; diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/herald/HeraldCommitAdapter.php phabricator-0~git20220903/phabricator/src/applications/diffusion/herald/HeraldCommitAdapter.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/herald/HeraldCommitAdapter.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/herald/HeraldCommitAdapter.php 2022-06-14 16:29:55.000000000 +0000 @@ -166,8 +166,8 @@ public function loadAuditNeededPackages() { if ($this->auditNeededPackages === null) { $status_arr = array( - PhabricatorAuditStatusConstants::AUDIT_REQUIRED, - PhabricatorAuditStatusConstants::CONCERNED, + PhabricatorAuditRequestStatus::AUDIT_REQUIRED, + PhabricatorAuditRequestStatus::CONCERNED, ); $requests = id(new PhabricatorRepositoryAuditRequest()) ->loadAllWhere( @@ -267,6 +267,11 @@ $raw = $diff_file->loadFileData(); + // See T13667. This happens when a commit is empty and affects no files. + if (!strlen($raw)) { + return false; + } + $parser = new ArcanistDiffParser(); $changes = $parser->parseDiff($raw); @@ -290,6 +295,10 @@ } } + if ($this->commitDiff === false) { + return array(); + } + if ($this->commitDiff instanceof Exception) { $ex = $this->commitDiff; $ex_class = get_class($ex); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php phabricator-0~git20220903/phabricator/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -46,6 +46,7 @@ return array( $this->buildStorageStatusPanel(), $this->buildClusterStatusPanel(), + $this->buildRefsStatusPanels(), ); } @@ -88,7 +89,7 @@ AlmanacClusterRepositoryServiceType::SERVICETYPE, )) ->withPHIDs(array($service_phid)) - ->needBindings(true) + ->needActiveBindings(true) ->executeOne(); if (!$service) { // TODO: Viewer may not have permission to see the service, or it may @@ -103,7 +104,7 @@ $rows = array(); if ($service) { - $bindings = $service->getBindings(); + $bindings = $service->getActiveBindings(); $bindings = mgroup($bindings, 'getDevicePHID'); // This is an unusual read which always comes from the master. @@ -116,29 +117,19 @@ $versions = mpull($versions, null, 'getDevicePHID'); - // List enabled devices first, then sort devices in each group by name. $sort = array(); foreach ($bindings as $key => $binding_group) { - $all_disabled = $this->isDisabledGroup($binding_group); - $sort[$key] = id(new PhutilSortVector()) - ->addInt($all_disabled ? 1 : 0) ->addString(head($binding_group)->getDevice()->getName()); } $sort = msortv($sort, 'getSelf'); $bindings = array_select_keys($bindings, array_keys($sort)) + $bindings; foreach ($bindings as $binding_group) { - $all_disabled = $this->isDisabledGroup($binding_group); $any_binding = head($binding_group); - if ($all_disabled) { - $binding_icon = 'fa-times grey'; - $binding_tip = pht('Disabled'); - } else { - $binding_icon = 'fa-folder-open green'; - $binding_tip = pht('Active'); - } + $binding_icon = 'fa-folder-open green'; + $binding_tip = pht('Active'); $binding_icon = id(new PHUIIconView()) ->setIcon($binding_icon) @@ -199,15 +190,19 @@ } } + $last_writer = null; + $writer_epoch = null; if ($write_properties) { $writer_phid = idx($write_properties, 'userPHID'); - $last_writer = $viewer->renderHandle($writer_phid); + + if ($writer_phid) { + $last_writer = $viewer->renderHandle($writer_phid); + } $writer_epoch = idx($write_properties, 'epoch'); - $writer_epoch = phabricator_datetime($writer_epoch, $viewer); - } else { - $last_writer = null; - $writer_epoch = null; + if ($writer_epoch) { + $writer_epoch = phabricator_datetime($writer_epoch, $viewer); + } } $rows[] = array( @@ -250,16 +245,129 @@ return $this->newBox(pht('Cluster Status'), $table); } - private function isDisabledGroup(array $binding_group) { - assert_instances_of($binding_group, 'AlmanacBinding'); + private function buildRefsStatusPanels() { + $repository = $this->getRepository(); + + $service_phid = $repository->getAlmanacServicePHID(); + if (!$service_phid) { + // If this repository isn't clustered, don't bother rendering anything. + // There are enough other context clues that another empty panel isn't + // useful. + return; + } + + $all_protocols = array( + 'http', + 'https', + 'ssh', + ); + + $readable_panel = $this->buildRefsStatusPanel( + pht('Readable Service Refs'), + array( + 'neverProxy' => false, + 'protocols' => $all_protocols, + 'writable' => false, + )); + + $writable_panel = $this->buildRefsStatusPanel( + pht('Writable Service Refs'), + array( + 'neverProxy' => false, + 'protocols' => $all_protocols, + 'writable' => true, + )); + + return array( + $readable_panel, + $writable_panel, + ); + } + + private function buildRefsStatusPanel( + $title, + $options) { + + $repository = $this->getRepository(); + $viewer = $this->getViewer(); + + $caught = null; + try { + $refs = $repository->getAlmanacServiceRefs($viewer, $options); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + $info_view = null; + if ($caught) { + $refs = array(); + $info_view = id(new PHUIInfoView()) + ->setErrors( + array( + phutil_escape_html_newlines($caught->getMessage()), + )); + } + + $phids = array(); + foreach ($refs as $ref) { + $phids[] = $ref->getDevicePHID(); + } + + $handles = $viewer->loadHandles($phids); + + $icon_writable = id(new PHUIIconView()) + ->setIcon('fa-pencil', 'green'); + + $icon_unwritable = id(new PHUIIconView()) + ->setIcon('fa-times', 'grey'); - foreach ($binding_group as $binding) { - if (!$binding->getIsDisabled()) { - return false; + $rows = array(); + foreach ($refs as $ref) { + $device_phid = $ref->getDevicePHID(); + $device_handle = $handles[$device_phid]; + + if ($ref->isWritable()) { + $writable_icon = $icon_writable; + $writable_text = pht('Read/Write'); + } else { + $writable_icon = $icon_unwritable; + $writable_text = pht('Read Only'); } + + $rows[] = array( + $device_handle->renderLink(), + $ref->getURI(), + $writable_icon, + $writable_text, + ); + } + + $table = id(new AphrontTableView($rows)) + ->setNoDataString(pht('No repository service refs available.')) + ->setHeaders( + array( + pht('Device'), + pht('Internal Service URI'), + null, + pht('I/O'), + )) + ->setColumnClasses( + array( + null, + 'wide', + 'icon', + null, + )); + + $box_view = $this->newBox($title, $table); + + if ($info_view) { + $box_view->setInfoView($info_view); } - return true; + return $box_view; } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php phabricator-0~git20220903/phabricator/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -130,19 +130,19 @@ $messages = array(); if ($repository->isHosted()) { if ($is_new) { - $host_message = pht('Phabricator will host this repository.'); + $host_message = pht('This repository will be hosted.'); } else { - $host_message = pht('Phabricator is hosting this repository.'); + $host_message = pht('This repository is observed.'); } $messages[] = $host_message; } else { if ($is_new) { $observe_message = pht( - 'Phabricator will observe a remote repository.'); + 'This repository will be observed.'); } else { $observe_message = pht( - 'This repository is hosted remotely. Phabricator is observing it.'); + 'This remote repository is being observed.'); } $messages[] = $observe_message; diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php phabricator-0~git20220903/phabricator/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -114,7 +114,7 @@ ->setUser($viewer) ->appendRemarkupInstructions( pht( - 'To access repositories hosted by Phabricator over HTTP, you must '. + 'To access repositories hosted on this server over HTTP, you must '. 'set a version control password. This password should be unique.'. "\n\n". "This password applies to all repositories available over ". diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionCommandEngine.php phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionCommandEngine.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionCommandEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionCommandEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -117,12 +117,16 @@ return $this->sudoAsDaemon; } + protected function shouldAlwaysSudo() { + return false; + } + public function newFuture() { $argv = $this->newCommandArgv(); $env = $this->newCommandEnvironment(); $is_passthru = $this->getPassthru(); - if ($this->getSudoAsDaemon()) { + if ($this->getSudoAsDaemon() || $this->shouldAlwaysSudo()) { $command = call_user_func_array('csprintf', $argv); $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); $argv = array('%C', $command); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionGitCommandEngine.php phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionGitCommandEngine.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionGitCommandEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionGitCommandEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,6 +13,20 @@ return array($pattern, $argv); } + protected function shouldAlwaysSudo() { + + // See T13673. In Git, always try to use "sudo" to execute commands as the + // daemon user (if such a user is configured), because Git 2.35.2 and newer + // (and some older versions of Git with backported security patches) refuse + // to execute if the top level repository directory is not owned by the + // current user. + + // Previously, we used "sudo" only when performing writes to the + // repository directory. + + return true; + } + protected function newCustomEnvironment() { $env = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -71,12 +71,36 @@ // // Separately, it may fail to write to a different branch cache, and may // encounter issues reading the branch cache. + // + // When Mercurial repositories are hosted on external systems with + // multi-user environments it's possible that the branch cache is computed + // on a revision which does not end up being published. When this happens it + // will recompute the cache but also print out "invalid branch cache". + // + // https://www.mercurial-scm.org/pipermail/mercurial/2014-June/047239.html + // + // When observing a repository which uses largefiles, the debug output may + // also contain extraneous output about largefile changes. + // + // At some point Mercurial added/improved support for pager used when + // command output is large. It includes printing out debug information that + // the pager is being started for a command. This seems to happen despite + // the output of the command being piped/read from another process. + // + // When printing color output Mercurial may run into some issue with the + // terminal info. This should never happen in Phabricator since color + // output should be turned off, however in the event it shows up we should + // filter it out anyways. $ignore = array( 'ignoring untrusted configuration option', "couldn't write revision branch cache:", "couldn't write branch cache:", 'invalid branchheads cache', + 'invalid branch cache', + 'updated patterns: .hglf', + 'starting pager for command', + 'no terminfo entry for', ); foreach ($ignore as $key => $pattern) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,6 +11,7 @@ private $repository; private $viewer; + private $actingAsPHID; private $logger; private $clusterWriteLock; @@ -44,6 +45,23 @@ return $this; } + public function setActingAsPHID($acting_as_phid) { + $this->actingAsPHID = $acting_as_phid; + return $this; + } + + public function getActingAsPHID() { + return $this->actingAsPHID; + } + + private function getEffectiveActingAsPHID() { + if ($this->actingAsPHID) { + return $this->actingAsPHID; + } + + return $this->getViewer()->getPHID(); + } + /* -( Cluster Synchronization )-------------------------------------------- */ @@ -255,9 +273,10 @@ throw new Exception( pht( 'Repository "%s" exists on more than one device, but no device '. - 'has any repository version information. Phabricator can not '. - 'guess which copy of the existing data is authoritative. Promote '. - 'a device or see "Ambiguous Leaders" in the documentation.', + 'has any repository version information. There is no way for the '. + 'software to determine which copy of the existing data is '. + 'authoritative. Promote a device or see "Ambiguous Leaders" in '. + 'the documentation.', $repository->getDisplayName())); } @@ -311,13 +330,18 @@ $write_lock = PhabricatorRepositoryWorkingCopyVersion::getWriteLock( $repository_phid); - $write_lock->useSpecificConnection($locked_connection); + $write_lock->setExternalConnection($locked_connection); $this->logLine( pht( 'Acquiring write lock for repository "%s"...', $repository->getDisplayName())); + // See T13590. On the HTTP pathway, it's possible for us to hit the script + // time limit while holding the durable write lock if a user makes a big + // push. Remove the time limit before we acquire the durable lock. + set_time_limit(0); + $lock_wait = phutil_units('2 minutes in seconds'); try { $write_wait_start = microtime(true); @@ -397,7 +421,7 @@ $repository_phid, $device_phid, array( - 'userPHID' => $viewer->getPHID(), + 'userPHID' => $this->getEffectiveActingAsPHID(), 'epoch' => PhabricatorTime::getNow(), 'devicePHID' => $device_phid, ), @@ -428,8 +452,6 @@ return; } - $viewer = $this->getViewer(); - $device = AlmanacKeys::getLiveDevice(); $device_phid = $device->getPHID(); @@ -880,4 +902,41 @@ new PhutilNumber($duration))); } + public function newMaintenanceEvent() { + $viewer = $this->getViewer(); + $repository = $this->getRepository(); + $now = PhabricatorTime::getNow(); + + $event = PhabricatorRepositoryPushEvent::initializeNewEvent($viewer) + ->setRepositoryPHID($repository->getPHID()) + ->setEpoch($now) + ->setPusherPHID($this->getEffectiveActingAsPHID()) + ->setRejectCode(PhabricatorRepositoryPushLog::REJECT_ACCEPT); + + return $event; + } + + public function newMaintenanceLog() { + $viewer = $this->getViewer(); + $repository = $this->getRepository(); + $now = PhabricatorTime::getNow(); + + $device = AlmanacKeys::getLiveDevice(); + if ($device) { + $device_phid = $device->getPHID(); + } else { + $device_phid = null; + } + + return PhabricatorRepositoryPushLog::initializeNewLog($viewer) + ->setDevicePHID($device_phid) + ->setRepositoryPHID($repository->getPHID()) + ->attachRepository($repository) + ->setEpoch($now) + ->setPusherPHID($this->getEffectiveActingAsPHID()) + ->setChangeFlags(PhabricatorRepositoryPushLog::CHANGEFLAG_MAINTENANCE) + ->setRefType(PhabricatorRepositoryPushLog::REFTYPE_MAINTENANCE) + ->setRefNew(''); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,89 @@ +<?php + +final class DiffusionMercurialCommandEngineTests extends PhabricatorTestCase { + + public function testFilteringDebugOutput() { + $map = array( + '' => '', + + "quack\n" => "quack\n", + + "ignoring untrusted configuration option x.y = z\nquack\n" => + "quack\n", + + "ignoring untrusted configuration option x.y = z\n". + "ignoring untrusted configuration option x.y = z\n". + "quack\n" => + "quack\n", + + "ignoring untrusted configuration option x.y = z\n". + "ignoring untrusted configuration option x.y = z\n". + "ignoring untrusted configuration option x.y = z\n". + "quack\n" => + "quack\n", + + "quack\n". + "ignoring untrusted configuration option x.y = z\n". + "ignoring untrusted configuration option x.y = z\n". + "ignoring untrusted configuration option x.y = z\n" => + "quack\n", + + "ignoring untrusted configuration option x.y = z\n". + "ignoring untrusted configuration option x.y = z\n". + "duck\n". + "ignoring untrusted configuration option x.y = z\n". + "ignoring untrusted configuration option x.y = z\n". + "bread\n". + "ignoring untrusted configuration option x.y = z\n". + "quack\n" => + "duck\nbread\nquack\n", + + "ignoring untrusted configuration option x.y = z\n". + "duckignoring untrusted configuration option x.y = z\n". + "quack" => + 'duckquack', + ); + + foreach ($map as $input => $expect) { + $actual = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( + $input); + $this->assertEqual($expect, $actual, $input); + } + + // Output that should be filtered out from the results + $output = + "ignoring untrusted configuration option\n". + "couldn't write revision branch cache:\n". + "couldn't write branch cache: blah blah blah\n". + "invalid branchheads cache\n". + "invalid branch cache (served): tip differs\n". + "starting pager for command 'log'\n". + "updated patterns: ". + ".hglf/project/src/a/b/c/SomeClass.java, ". + "project/src/a/b/c/SomeClass.java\n". + "no terminfo entry for sitm\n"; + + $filtered_output = + DiffusionMercurialCommandEngine::filterMercurialDebugOutput($output); + + $this->assertEqual('', $filtered_output); + + // The output that should make it through the filtering + $output = + "0b33a9e5ceedba14b03214f743957357d7bb46a9;694". + ":8b39f63eb209dd2bdfd4bd3d0721a9e38d75a6d3". + "-1:0000000000000000000000000000000000000000\n". + "8b39f63eb209dd2bdfd4bd3d0721a9e38d75a6d3;693". + ":165bce9ce4ccc97024ba19ed5a22f6a066fa6844". + "-1:0000000000000000000000000000000000000000\n". + "165bce9ce4ccc97024ba19ed5a22f6a066fa6844;692:". + "2337bc9e3cf212b3b386b5197801b1c81db64920". + "-1:0000000000000000000000000000000000000000\n"; + + $filtered_output = + DiffusionMercurialCommandEngine::filterMercurialDebugOutput($output); + + $this->assertEqual($output, $filtered_output); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/blame/DiffusionGitBlameQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/blame/DiffusionGitBlameQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/blame/DiffusionGitBlameQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/blame/DiffusionGitBlameQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,7 +13,7 @@ return $repository->getLocalCommandFuture( '--no-pager blame --root -s -l %s -- %s', - $commit, + gitsprintf('%s', $commit), $path); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,11 +6,26 @@ $repository = $request->getRepository(); $commit = $request->getCommit(); - // NOTE: We're using "--debug" to make "--changeset" give us the full - // commit hashes. + // NOTE: Using "--template" or "--debug" to get the full commit hashes. + $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg'); + if ($hg_analyzer->isMercurialAnnotateTemplatesAvailable()) { + // See `hg help annotate --verbose` for more info on the template format. + // Use array of arguments so the template line does not need wrapped in + // quotes. + $template = array( + '--template', + "{lines % '{node}: {line}'}", + ); + } else { + $template = array( + '--debug', + '--changeset', + ); + } return $repository->getLocalCommandFuture( - 'annotate --debug --changeset --rev %s -- %s', + 'annotate %Ls --rev %s -- %s', + $template, $commit, $path); } @@ -26,6 +41,21 @@ $lines = phutil_split_lines($stdout); foreach ($lines as $line) { + // If the `--debug` flag was used above instead of `--template` then + // there's a good change additional output was included which is not + // relevant to the information we want. It should be safe to call this + // regardless of whether we used `--debug` or `--template` so there isn't + // a need to track which argument was used. + $line = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( + $line); + + // Just in case new versions of Mercurial add arbitrary output when using + // the `--debug`, do a quick sanity check that this line is formatted in + // a way we're expecting. + if (strpos($line, ':') === false) { + phlog(pht('Unexpected output from hg annotate: %s', $line)); + continue; + } list($commit) = explode(':', $line, 2); $result[] = $commit; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/DiffusionCommitHintQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/DiffusionCommitHintQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/DiffusionCommitHintQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/DiffusionCommitHintQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -56,10 +56,6 @@ $this->commitMap = array(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/DiffusionCommitQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/DiffusionCommitQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/DiffusionCommitQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/DiffusionCommitQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,7 +15,7 @@ private $statuses; private $packagePHIDs; private $unreachable; - private $unpublished; + private $permanent; private $needAuditRequests; private $needAuditAuthority; @@ -154,8 +154,8 @@ return $this; } - public function withUnpublished($unpublished) { - $this->unpublished = $unpublished; + public function withPermanent($permanent) { + $this->permanent = $permanent; return $this; } @@ -859,18 +859,18 @@ } } - if ($this->unpublished !== null) { - if ($this->unpublished) { + if ($this->permanent !== null) { + if ($this->permanent) { $where[] = qsprintf( $conn, - '(commit.importStatus & %d) = 0', - PhabricatorRepositoryCommit::IMPORTED_CLOSEABLE); + '(commit.importStatus & %d) = %d', + PhabricatorRepositoryCommit::IMPORTED_PERMANENT, + PhabricatorRepositoryCommit::IMPORTED_PERMANENT); } else { $where[] = qsprintf( $conn, - '(commit.importStatus & %d) = %d', - PhabricatorRepositoryCommit::IMPORTED_CLOSEABLE, - PhabricatorRepositoryCommit::IMPORTED_CLOSEABLE); + '(commit.importStatus & %d) = 0', + PhabricatorRepositoryCommit::IMPORTED_PERMANENT); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php 2022-06-14 16:29:55.000000000 +0000 @@ -90,7 +90,7 @@ $objects = $this->objects; $has_concern = array( - PhabricatorAuditStatusConstants::CONCERNED, + PhabricatorAuditRequestStatus::CONCERNED, ); $has_concern = array_fuse($has_concern); @@ -119,8 +119,8 @@ $objects = $this->objects; $should_audit = array( - PhabricatorAuditStatusConstants::AUDIT_REQUIRED, - PhabricatorAuditStatusConstants::AUDIT_REQUESTED, + PhabricatorAuditRequestStatus::AUDIT_REQUIRED, + PhabricatorAuditRequestStatus::AUDIT_REQUESTED, ); $should_audit = array_fuse($should_audit); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,9 +10,8 @@ $commit = $drequest->getCommit(); return $repository->getLocalCommandFuture( - 'cat-file blob %s:%s', - $commit, - $path); + 'cat-file blob -- %s', + sprintf('%s:%s', $commit, $path)); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -55,12 +55,15 @@ $split_body = true; } - // Even though we pass --encoding here, git doesn't always succeed, so - // we try a little harder, since git *does* tell us what the actual encoding - // is correctly (unless it doesn't; encoding is sometimes empty). - list($info) = $repository->execxLocalCommand( - 'log -n 1 --encoding=%s --format=%s %s --', - 'UTF-8', + $argv = array(); + + $argv[] = '-n'; + $argv[] = '1'; + + $argv[] = '--encoding=UTF-8'; + + $argv[] = sprintf( + '--format=%s', implode( '%x00', array( @@ -78,8 +81,15 @@ // so include an explicit terminator: this makes sure the exact // body text is surrounded by "\0" characters. '~', - )), - $this->identifier); + ))); + + // Even though we pass --encoding here, git doesn't always succeed, so + // we try a little harder, since git *does* tell us what the actual encoding + // is correctly (unless it doesn't; encoding is sometimes empty). + list($info) = $repository->execxLocalCommand( + 'log -n 1 %Ls %s --', + $argv, + gitsprintf('%s', $this->identifier)); $parts = explode("\0", $info); $encoding = array_shift($parts); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelFilesizeQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelFilesizeQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelFilesizeQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelFilesizeQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -33,7 +33,7 @@ $paths_future = $repository->getLocalCommandFuture( 'diff-tree -z -r --no-commit-id %s --', - $identifier); + gitsprintf('%s', $identifier)); // With "-z" we get "<fields>\0<filename>\0" for each line. Process the // delimited text as "<fields>, <filename>" pairs. diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -37,9 +37,9 @@ $repository = $this->getRepository(); list($stdout) = $repository->execxLocalCommand( - 'log -n 1 --format=%s %s', - '%P', - $this->identifier); + 'log -n 1 %s %s --', + '--format=%P', + gitsprintf('%s', $this->identifier)); return preg_split('/\s+/', trim($stdout)); } @@ -47,23 +47,23 @@ private function loadMercurialParents() { $repository = $this->getRepository(); + $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg'); + if ($hg_analyzer->isMercurialTemplatePnodeAvailable()) { + $hg_log_template = '{p1.node} {p2.node}'; + } else { + $hg_log_template = '{p1node} {p2node}'; + } + list($stdout) = $repository->execxLocalCommand( - 'log --debug --limit 1 --template={parents} --rev %s', + 'log --limit 1 --template %s --rev %s', + $hg_log_template, $this->identifier); - $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( - $stdout); - $hashes = preg_split('/\s+/', trim($stdout)); foreach ($hashes as $key => $value) { - // Mercurial parents look like "23:ad9f769d6f786fad9f76d9a" -- we want - // to strip out the local rev part. - list($local, $global) = explode(':', $value); - $hashes[$key] = $global; - - // With --debug we get 40-character hashes but also get the "000000..." - // hash for missing parents; ignore it. - if (preg_match('/^0+$/', $global)) { + // We get 40-character hashes but also get the "000000..." hash for + // missing parents; ignore it. + if (preg_match('/^0+\z/', $value)) { unset($hashes[$key]); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -63,48 +63,66 @@ $unresolved = array_fuse($this->refs); $results = array(); - // First, resolve branches and tags. - $ref_map = id(new DiffusionLowLevelGitRefQuery()) - ->setRepository($repository) - ->withRefTypes( - array( - PhabricatorRepositoryRefCursor::TYPE_BRANCH, - PhabricatorRepositoryRefCursor::TYPE_TAG, - )) - ->execute(); - $ref_map = mgroup($ref_map, 'getShortName'); - - $tag_prefix = 'refs/tags/'; + $possible_symbols = array(); foreach ($unresolved as $ref) { - if (empty($ref_map[$ref])) { + + // See T13647. If this symbol is exactly 40 hex characters long, it may + // never resolve as a branch or tag name. Filter these symbols out for + // consistency with Git behavior -- and to avoid an expensive + // "git for-each-ref" when resolving only commit hashes, which happens + // during repository updates. + + if (preg_match('(^[a-f0-9]{40}\z)', $ref)) { continue; } - foreach ($ref_map[$ref] as $result) { - $fields = $result->getRawFields(); - $objectname = idx($fields, 'refname'); - if (!strncmp($objectname, $tag_prefix, strlen($tag_prefix))) { - $type = 'tag'; - } else { - $type = 'branch'; + $possible_symbols[$ref] = $ref; + } + + // First, resolve branches and tags. + if ($possible_symbols) { + $ref_map = id(new DiffusionLowLevelGitRefQuery()) + ->setRepository($repository) + ->withRefTypes( + array( + PhabricatorRepositoryRefCursor::TYPE_BRANCH, + PhabricatorRepositoryRefCursor::TYPE_TAG, + )) + ->execute(); + $ref_map = mgroup($ref_map, 'getShortName'); + + $tag_prefix = 'refs/tags/'; + foreach ($possible_symbols as $ref) { + if (empty($ref_map[$ref])) { + continue; } - $info = array( - 'type' => $type, - 'identifier' => $result->getCommitIdentifier(), - ); - - if ($type == 'tag') { - $alternate = idx($fields, 'objectname'); - if ($alternate) { - $info['alternate'] = $alternate; + foreach ($ref_map[$ref] as $result) { + $fields = $result->getRawFields(); + $objectname = idx($fields, 'refname'); + if (!strncmp($objectname, $tag_prefix, strlen($tag_prefix))) { + $type = 'tag'; + } else { + $type = 'branch'; + } + + $info = array( + 'type' => $type, + 'identifier' => $result->getCommitIdentifier(), + ); + + if ($type == 'tag') { + $alternate = idx($fields, 'objectname'); + if ($alternate) { + $info['alternate'] = $alternate; + } } + + $results[$ref][] = $info; } - $results[$ref][] = $info; + unset($unresolved[$ref]); } - - unset($unresolved[$ref]); } // If we resolved everything, we're done. diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -88,7 +88,12 @@ $change->setFileType($raw_change['fileType']); $change->setCommitIdentifier($commit->getCommitIdentifier()); - $change->setTargetPath(ltrim($raw_change['targetPathName'], '/')); + $target_path = $raw_change['targetPathName']; + if ($target_path !== null) { + $target_path = ltrim($target_path, '/'); + } + $change->setTargetPath($target_path); + $change->setTargetCommitIdentifier($raw_change['targetCommitIdentifier']); $id = $raw_change['pathID']; diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php phabricator-0~git20220903/phabricator/src/applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -23,9 +23,9 @@ // Check if this is the root commit by seeing if it has parents, since // `git diff X^ X` does not work if "X" is the initial commit. list($parents) = $repository->execxLocalCommand( - 'log -n 1 --format=%s %s --', - '%P', - $commit); + 'log -n 1 %s %s --', + '--format=%P', + gitsprintf('%s', $commit)); if (strlen(trim($parents))) { $against = $commit.'^'; @@ -42,8 +42,8 @@ return $repository->getLocalCommandFuture( 'diff %Ls %s %s -- %s', $options, - $against, - $commit, + gitsprintf('%s', $against), + gitsprintf('%s', $commit), $path); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/request/DiffusionRequest.php phabricator-0~git20220903/phabricator/src/applications/diffusion/request/DiffusionRequest.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/request/DiffusionRequest.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/request/DiffusionRequest.php 2022-06-14 16:29:55.000000000 +0000 @@ -125,7 +125,7 @@ * * @task new */ - final private function __construct() { + private function __construct() { // <private> } @@ -138,7 +138,7 @@ * @return DiffusionRequest New request object. * @task new */ - final private static function newFromIdentifier( + private static function newFromIdentifier( $identifier, PhabricatorUser $viewer, $need_edit = false) { @@ -174,7 +174,7 @@ * @return DiffusionRequest New request object. * @task new */ - final private static function newFromRepository( + private static function newFromRepository( PhabricatorRepository $repository) { $map = array( @@ -205,9 +205,9 @@ * @return void * @task new */ - final private function initializeFromDictionary(array $data) { + private function initializeFromDictionary(array $data) { $blob = idx($data, 'blob'); - if (strlen($blob)) { + if (phutil_nonempty_string($blob)) { $blob = self::parseRequestBlob($blob, $this->supportsBranches()); $data = $blob + $data; } @@ -518,12 +518,14 @@ $result['path'] = $blob; } - $parts = explode('/', $result['path']); - foreach ($parts as $part) { - // Prevent any hyjinx since we're ultimately shipping this to the - // filesystem under a lot of workflows. - if ($part == '..') { - throw new Exception(pht('Invalid path URI.')); + if ($result['path'] !== null) { + $parts = explode('/', $result['path']); + foreach ($parts as $part) { + // Prevent any hyjinx since we're ultimately shipping this to the + // filesystem under a lot of workflows. + if ($part == '..') { + throw new Exception(pht('Invalid path URI.')); + } } } @@ -561,7 +563,7 @@ throw new DiffusionSetupException( pht( 'The working copy for this repository ("%s") has not been cloned yet '. - 'on this machine ("%s"). Make sure you havestarted the Phabricator '. + 'on this machine ("%s"). Make sure you have started the '. 'daemons. If this problem persists for longer than a clone should '. 'take, check the daemon logs (in the Daemon Console) to see if there '. 'were errors cloning the repository. Consult the "Diffusion User '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php phabricator-0~git20220903/phabricator/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -117,7 +117,7 @@ throw new Exception( pht( 'Unable to determine the username to connect with when trying '. - 'to proxy an SSH request within the Phabricator cluster.')); + 'to proxy an SSH request within the cluster.')); } $port = $uri->getPort(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/view/DiffusionBrowseTableView.php phabricator-0~git20220903/phabricator/src/applications/diffusion/view/DiffusionBrowseTableView.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/view/DiffusionBrowseTableView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/view/DiffusionBrowseTableView.php 2022-06-14 16:29:55.000000000 +0000 @@ -3,7 +3,6 @@ final class DiffusionBrowseTableView extends DiffusionView { private $paths; - private $handles = array(); public function setPaths(array $paths) { assert_instances_of($paths, 'DiffusionRepositoryPath'); @@ -11,12 +10,6 @@ return $this; } - public function setHandles(array $handles) { - assert_instances_of($handles, 'PhabricatorObjectHandle'); - $this->handles = $handles; - return $this; - } - public function render() { $request = $this->getDiffusionRequest(); $repository = $request->getRepository(); @@ -29,7 +22,6 @@ $need_pull = array(); $rows = array(); - $show_edit = false; foreach ($this->paths as $path) { $full_path = $base_path.$path->getPath(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/worker/DiffusionUpdateObjectAfterCommitWorker.php phabricator-0~git20220903/phabricator/src/applications/diffusion/worker/DiffusionUpdateObjectAfterCommitWorker.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/worker/DiffusionUpdateObjectAfterCommitWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/worker/DiffusionUpdateObjectAfterCommitWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -148,17 +148,39 @@ PhabricatorRepositoryCommit $commit, DifferentialRevision $revision) { + $acting_phid = $this->getActingPHID($commit); + $acting_user = $this->loadActingUser($acting_phid); + + // See T13625. The "Acting User" is the author of the commit based on the + // author string, or the Diffusion application PHID if we could not + // identify an author. + + // This user may not be able to view the commit or the revision, and may + // also be unable to make API calls. Here, we execute queries and apply + // transactions as the omnipotent user. + + // It would probably be better to use the acting user everywhere here, and + // exit gracefully if they can't see the revision (this is how the flow + // on tasks works). However, without a positive indicator in the UI + // explaining "no revision was updated because the author of this commit + // can't see anything", this might be fairly confusing, and break workflows + // which have worked historically. + + // This isn't, per se, a policy violation (you can't get access to anything + // you don't already have access to by making commits that reference + // revisions, even if you can't see the commits or revisions), so just + // leave it for now. + + $viewer = $this->getViewer(); + // Reload the revision to get the active diff, which is currently required // by "updateRevisionWithCommit()". $revision = id(new DifferentialRevisionQuery()) - ->setViewer($this->getViewer()) + ->setViewer($viewer) ->withIDs(array($revision->getID())) ->needActiveDiffs(true) ->executeOne(); - $acting_phid = $this->getActingPHID($commit); - $acting_user = $this->loadActingUser($acting_phid); - $xactions = array(); $xactions[] = $this->newEdgeTransaction( @@ -177,7 +199,7 @@ ->setMetadataValue('commitPHID', $commit->getPHID()); $extraction_engine = id(new DifferentialDiffExtractionEngine()) - ->setViewer($acting_user) + ->setViewer($viewer) ->setAuthorPHID($acting_phid); $content_source = $this->newContentSource(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitAcceptTransaction.php phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitAcceptTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitAcceptTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitAcceptTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -31,7 +31,7 @@ } public function applyExternalEffects($object, $value) { - $status = PhabricatorAuditStatusConstants::ACCEPTED; + $status = PhabricatorAuditRequestStatus::ACCEPTED; $actor = $this->getActor(); $this->applyAuditorEffect($object, $actor, $value, $status); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -16,7 +16,7 @@ $auditors = $this->generateOldValue($object); $old_auditors = $auditors; - $request_status = PhabricatorAuditStatusConstants::AUDIT_REQUESTED; + $request_status = PhabricatorAuditRequestStatus::AUDIT_REQUESTED; $rem = idx($value, '-', array()); foreach ($rem as $phid) { @@ -182,7 +182,7 @@ return $errors; } - $author_phid = $object->getAuthorPHID(); + $author_phid = $object->getEffectiveAuthorPHID(); $can_author_close_key = 'audit.can-author-close-audit'; $can_author_close = PhabricatorEnv::getEnvConfig($can_author_close_key); diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditTransaction.php phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitAuditTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,12 +21,12 @@ PhabricatorRepositoryCommit $commit, PhabricatorUser $viewer) { - // This omits various inactive states like "Resigned" and "Not Required". + // This omits inactive states; currently just "Resigned". $active = array( - PhabricatorAuditStatusConstants::AUDIT_REQUIRED, - PhabricatorAuditStatusConstants::CONCERNED, - PhabricatorAuditStatusConstants::ACCEPTED, - PhabricatorAuditStatusConstants::AUDIT_REQUESTED, + PhabricatorAuditRequestStatus::AUDIT_REQUIRED, + PhabricatorAuditRequestStatus::CONCERNED, + PhabricatorAuditRequestStatus::ACCEPTED, + PhabricatorAuditRequestStatus::AUDIT_REQUESTED, ); $active = array_fuse($active); @@ -42,7 +42,7 @@ $commit, $viewer, array( - PhabricatorAuditStatusConstants::ACCEPTED, + PhabricatorAuditRequestStatus::ACCEPTED, )); } @@ -53,7 +53,7 @@ $commit, $viewer, array( - PhabricatorAuditStatusConstants::CONCERNED, + PhabricatorAuditRequestStatus::CONCERNED, )); } @@ -117,7 +117,7 @@ $map = array(); - $with_authority = ($status != PhabricatorAuditStatusConstants::RESIGNED); + $with_authority = ($status != PhabricatorAuditRequestStatus::RESIGNED); if ($with_authority) { foreach ($audits as $audit) { if ($commit->hasAuditAuthority($actor, $audit, $acting_phid)) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitConcernTransaction.php phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitConcernTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitConcernTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitConcernTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -37,7 +37,7 @@ } public function applyExternalEffects($object, $value) { - $status = PhabricatorAuditStatusConstants::CONCERNED; + $status = PhabricatorAuditRequestStatus::CONCERNED; $actor = $this->getActor(); $this->applyAuditorEffect($object, $actor, $value, $status); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitResignTransaction.php phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitResignTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/diffusion/xaction/DiffusionCommitResignTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diffusion/xaction/DiffusionCommitResignTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -36,7 +36,7 @@ } public function applyExternalEffects($object, $value) { - $status = PhabricatorAuditStatusConstants::RESIGNED; + $status = PhabricatorAuditRequestStatus::RESIGNED; $actor = $this->getActor(); $this->applyAuditorEffect($object, $actor, $value, $status); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/diviner/controller/DivinerMainController.php phabricator-0~git20220903/phabricator/src/applications/diviner/controller/DivinerMainController.php --- phabricator-0~git20200925/phabricator/src/applications/diviner/controller/DivinerMainController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/diviner/controller/DivinerMainController.php 2022-06-14 16:29:55.000000000 +0000 @@ -48,18 +48,20 @@ $document->appendChild($list); } else { $text = pht( - "(NOTE) **Looking for Phabricator documentation?** ". - "If you're looking for help and information about Phabricator, ". + "(NOTE) **Looking for documentation?** ". + "If you're looking for help and information about %s, ". "you can [[https://secure.phabricator.com/diviner/ | ". - "browse the public Phabricator documentation]] on the live site.\n\n". - "Diviner is the documentation generator used to build the ". - "Phabricator documentation.\n\n". + "browse the public %s documentation]] on the live site.\n\n". + "Diviner is the documentation generator used to build this ". + "documentation.\n\n". "You haven't generated any Diviner documentation books yet, so ". "there's nothing to show here. If you'd like to generate your own ". - "local copy of the Phabricator documentation and have it appear ". + "local copy of the documentation and have it appear ". "here, run this command:\n\n". " %s\n\n", - 'phabricator/ $ ./bin/diviner generate'); + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName(), + '$ ./bin/diviner generate'); $text = new PHUIRemarkupView($viewer, $text); $document->appendChild($text); diff -Nru phabricator-0~git20200925/phabricator/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -33,12 +33,14 @@ ->setSummary(pht('Optional Asana projects to use as application tags.')) ->setDescription( pht( - 'When Phabricator creates tasks in Asana, it can add the tasks '. + 'When %s creates tasks in Asana, it can add the tasks '. 'to Asana projects based on which application the corresponding '. - 'object in Phabricator comes from. For example, you can add code '. + 'object in %s comes from. For example, you can add code '. 'reviews in Asana to a "Differential" project.'. "\n\n". - 'NOTE: This feature is new and experimental.')), + 'NOTE: This feature is new and experimental.', + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName())), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php phabricator-0~git20220903/phabricator/src/applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php --- phabricator-0~git20200925/phabricator/src/applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -20,10 +20,6 @@ return new DoorkeeperExternalObject(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/doorkeeper/worker/DoorkeeperAsanaFeedWorker.php phabricator-0~git20220903/phabricator/src/applications/doorkeeper/worker/DoorkeeperAsanaFeedWorker.php --- phabricator-0~git20200925/phabricator/src/applications/doorkeeper/worker/DoorkeeperAsanaFeedWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/doorkeeper/worker/DoorkeeperAsanaFeedWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -512,9 +512,10 @@ private function getSynchronizationWarning() { return pht( "\xE2\x9A\xA0 DO NOT EDIT THIS TASK \xE2\x9A\xA0\n". - "\xE2\x98\xA0 Your changes will not be reflected in Phabricator.\n". + "\xE2\x98\xA0 Your changes will not be reflected in %s.\n". "\xE2\x98\xA0 Your changes will be destroyed the next time state ". - "is synchronized."); + "is synchronized.", + PlatformSymbols::getPlatformServerName()); } private function lookupAsanaUserIDs($all_phids) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/doorkeeper/worker/DoorkeeperFeedWorker.php phabricator-0~git20220903/phabricator/src/applications/doorkeeper/worker/DoorkeeperFeedWorker.php --- phabricator-0~git20200925/phabricator/src/applications/doorkeeper/worker/DoorkeeperFeedWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/doorkeeper/worker/DoorkeeperFeedWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -158,7 +158,7 @@ */ final protected function doWork() { if (PhabricatorEnv::getEnvConfig('phabricator.silent')) { - $this->log("%s\n", pht('Phabricator is running in silent mode.')); + $this->log("%s\n", pht('This software is running in silent mode.')); return; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php phabricator-0~git20220903/phabricator/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,7 +34,7 @@ DrydockBlueprint $blueprint, DrydockLease $lease) { $services = $this->loadServices($blueprint); - $bindings = $this->loadAllBindings($services); + $bindings = $this->getActiveBindings($services); if (!$bindings) { // If there are no devices bound to the services for this blueprint, @@ -222,7 +222,7 @@ ->setViewer($viewer) ->withPHIDs($service_phids) ->withServiceTypes($this->getAlmanacServiceTypes()) - ->needBindings(true) + ->needActiveBindings(true) ->execute(); $services = mpull($services, null, 'getPHID'); @@ -242,9 +242,9 @@ return $this->services; } - private function loadAllBindings(array $services) { + private function getActiveBindings(array $services) { assert_instances_of($services, 'AlmanacService'); - $bindings = array_mergev(mpull($services, 'getBindings')); + $bindings = array_mergev(mpull($services, 'getActiveBindings')); return mpull($bindings, null, 'getPHID'); } @@ -271,15 +271,10 @@ $allocated_phids = array_fuse($allocated_phids); $services = $this->loadServices($blueprint); - $bindings = $this->loadAllBindings($services); + $bindings = $this->getActiveBindings($services); $free = array(); foreach ($bindings as $binding) { - // Don't consider disabled bindings to be available. - if ($binding->getIsDisabled()) { - continue; - } - if (empty($allocated_phids[$binding->getPHID()])) { $free[] = $binding; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php phabricator-0~git20220903/phabricator/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php 2022-06-14 16:29:55.000000000 +0000 @@ -329,6 +329,47 @@ ->execute(); } + + /** + * Get all the @{class:DrydockBlueprintImplementation}s which can possibly + * build a resource to satisfy a lease. + * + * This method returns blueprints which might, at some time, be able to + * build a resource which can satisfy the lease. They may not be able to + * build that resource right now. + * + * @param DrydockLease Requested lease. + * @return list<DrydockBlueprintImplementation> List of qualifying blueprint + * implementations. + */ + public static function getAllForAllocatingLease( + DrydockLease $lease) { + + $impls = self::getAllBlueprintImplementations(); + + $keep = array(); + foreach ($impls as $key => $impl) { + // Don't use disabled blueprint types. + if (!$impl->isEnabled()) { + continue; + } + + // Don't use blueprint types which can't allocate the correct kind of + // resource. + if ($impl->getType() != $lease->getResourceType()) { + continue; + } + + if (!$impl->canAnyBlueprintEverAllocateResourceForLease($lease)) { + continue; + } + + $keep[$key] = $impl; + } + + return $keep; + } + public static function getNamedImplementation($class) { return idx(self::getAllBlueprintImplementations(), $class); } @@ -465,28 +506,21 @@ protected function shouldLimitAllocatingPoolSize( DrydockBlueprint $blueprint) { - // TODO: If this mechanism sticks around, these values should be - // configurable by the blueprint implementation. - // Limit on total number of active resources. $total_limit = $this->getConcurrentResourceLimit($blueprint); - - // Always allow at least this many allocations to be in flight at once. - $min_allowed = 1; - - // Allow this fraction of allocating resources as a fraction of active - // resources. - $growth_factor = 0.25; + if ($total_limit === null) { + return false; + } $resource = new DrydockResource(); - $conn_r = $resource->establishConnection('r'); + $conn = $resource->establishConnection('r'); $counts = queryfx_all( - $conn_r, - 'SELECT status, COUNT(*) N FROM %T + $conn, + 'SELECT status, COUNT(*) N FROM %R WHERE blueprintPHID = %s AND status != %s GROUP BY status', - $resource->getTableName(), + $resource, $blueprint->getPHID(), DrydockResourceStatus::STATUS_DESTROYED); $counts = ipull($counts, 'N', 'status'); @@ -498,29 +532,12 @@ // If we're at the limit on total active resources, limit additional // allocations. - if ($total_limit !== null) { - $n_total = ($n_alloc + $n_active + $n_broken + $n_released); - if ($n_total >= $total_limit) { - return true; - } + $n_total = ($n_alloc + $n_active + $n_broken + $n_released); + if ($n_total >= $total_limit) { + return true; } - // If the number of in-flight allocations is fewer than the minimum number - // of allowed allocations, don't impose a limit. - if ($n_alloc < $min_allowed) { - return false; - } - - $allowed_alloc = (int)ceil($n_active * $growth_factor); - - // If the number of in-flight allocation is fewer than the number of - // allowed allocations according to the pool growth factor, don't impose - // a limit. - if ($n_alloc < $allowed_alloc) { - return false; - } - - return true; + return false; } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php phabricator-0~git20220903/phabricator/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php 2022-06-14 16:29:55.000000000 +0000 @@ -43,11 +43,6 @@ return false; } - // TODO: If we have a pending resource which is compatible with the - // configuration for this lease, prevent a new allocation? Otherwise the - // queue can fill up with copies of requests from the same lease. But - // maybe we can deal with this with "pre-leasing"? - return true; } @@ -135,14 +130,7 @@ ->setAllowedBlueprintPHIDs($blueprint_phids); $resource->setAttribute('host.leasePHID', $host_lease->getPHID()); - $map = $lease->getAttribute('repositories.map'); - foreach ($map as $key => $value) { - $map[$key] = array_select_keys( - $value, - array( - 'phid', - )); - } + $map = $this->getWorkingCopyRepositoryMap($lease); $resource->setAttribute('repositories.map', $map); $slot_lock = $this->getConcurrentResourceLimitSlotLock($blueprint); @@ -157,6 +145,44 @@ return $resource; } + private function getWorkingCopyRepositoryMap(DrydockLease $lease) { + $attribute = 'repositories.map'; + $map = $lease->getAttribute($attribute); + + // TODO: Leases should validate their attributes more formally. + + if (!is_array($map) || !$map) { + $message = array(); + if ($map === null) { + $message[] = pht( + 'Working copy lease is missing required attribute "%s".', + $attribute); + } else { + $message[] = pht( + 'Working copy lease has invalid attribute "%s".', + $attribute); + } + + $message[] = pht( + 'Attribute "repositories.map" should be a map of repository '. + 'specifications.'); + + $message = implode("\n\n", $message); + + throw new Exception($message); + } + + foreach ($map as $key => $value) { + $map[$key] = array_select_keys( + $value, + array( + 'phid', + )); + } + + return $map; + } + public function activateResource( DrydockBlueprint $blueprint, DrydockResource $resource) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForActivationLogType.php phabricator-0~git20220903/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForActivationLogType.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForActivationLogType.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForActivationLogType.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,23 @@ +<?php + +final class DrydockLeaseWaitingForActivationLogType extends DrydockLogType { + + const LOGCONST = 'core.lease.waiting-for-activation'; + + public function getLogTypeName() { + return pht('Waiting For Activation'); + } + + public function getLogTypeIcon(array $data) { + return 'fa-clock-o yellow'; + } + + public function renderLog(array $data) { + $resource_phids = idx($data, 'resourcePHIDs', array()); + + return pht( + 'Waiting for activation of resources: %s.', + $this->renderHandleList($resource_phids)); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForReclamationLogType.php phabricator-0~git20220903/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForReclamationLogType.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForReclamationLogType.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/logtype/DrydockLeaseWaitingForReclamationLogType.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,23 @@ +<?php + +final class DrydockLeaseWaitingForReclamationLogType extends DrydockLogType { + + const LOGCONST = 'core.lease.waiting-for-reclamation'; + + public function getLogTypeName() { + return pht('Waiting For Reclamation'); + } + + public function getLogTypeIcon(array $data) { + return 'fa-clock-o yellow'; + } + + public function renderLog(array $data) { + $resource_phids = idx($data, 'resourcePHIDs', array()); + + return pht( + 'Waiting for reclamation of resources: %s.', + $this->renderHandleList($resource_phids)); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementCommandWorkflow.php phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementCommandWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementCommandWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementCommandWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -27,8 +27,7 @@ if (!$lease_id) { throw new PhutilArgumentUsageException( pht( - 'Use %s to specify a lease.', - '--lease')); + 'Use "--lease" to specify a lease.')); } $argv = $args->getArg('argv'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,6 +26,18 @@ 'JSON file with lease attributes. Use "-" to read attributes '. 'from stdin.'), ), + array( + 'name' => 'count', + 'param' => 'N', + 'default' => 1, + 'help' => pht('Lease a given number of identical resources.'), + ), + array( + 'name' => 'blueprint', + 'param' => 'identifier', + 'repeat' => true, + 'help' => pht('Lease resources from a specific blueprint.'), + ), )); } @@ -33,30 +45,36 @@ $viewer = $this->getViewer(); $resource_type = $args->getArg('type'); - if (!$resource_type) { + if (!phutil_nonempty_string($resource_type)) { throw new PhutilArgumentUsageException( pht( - 'Specify a resource type with `%s`.', - '--type')); + 'Specify a resource type with "--type".')); } $until = $args->getArg('until'); - if (strlen($until)) { + if (phutil_nonempty_string($until)) { $until = strtotime($until); if ($until <= 0) { throw new PhutilArgumentUsageException( pht( - 'Unable to parse argument to "%s".', - '--until')); + 'Unable to parse argument to "--until".')); } } + $count = $args->getArgAsInteger('count'); + if ($count < 1) { + throw new PhutilArgumentUsageException( + pht( + 'Value provided to "--count" must be a nonzero, positive '. + 'number.')); + } + $attributes_file = $args->getArg('attributes'); - if (strlen($attributes_file)) { + if (phutil_nonempty_string($attributes_file)) { if ($attributes_file == '-') { echo tsprintf( "%s\n", - 'Reading JSON attributes from stdin...'); + pht('Reading JSON attributes from stdin...')); $data = file_get_contents('php://stdin'); } else { $data = Filesystem::readFile($attributes_file); @@ -67,38 +85,46 @@ $attributes = array(); } - $lease = id(new DrydockLease()) - ->setResourceType($resource_type); + $filter_identifiers = $args->getArg('blueprint'); + if ($filter_identifiers) { + $filter_blueprints = $this->getBlueprintFilterMap($filter_identifiers); + } else { + $filter_blueprints = array(); + } - $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); - $lease->setAuthorizingPHID($drydock_phid); + $blueprint_phids = null; - if ($attributes) { - $lease->setAttributes($attributes); - } + $leases = array(); + for ($idx = 0; $idx < $count; $idx++) { + $lease = id(new DrydockLease()) + ->setResourceType($resource_type); - // TODO: This is not hugely scalable, although this is a debugging workflow - // so maybe it's fine. Do we even need `bin/drydock lease` in the long run? - $all_blueprints = id(new DrydockBlueprintQuery()) - ->setViewer($viewer) - ->execute(); - $allowed_phids = mpull($all_blueprints, 'getPHID'); - if (!$allowed_phids) { - throw new Exception( - pht( - 'No blueprints exist which can plausibly allocate resources to '. - 'satisfy the requested lease.')); - } - $lease->setAllowedBlueprintPHIDs($allowed_phids); + $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); + $lease->setAuthorizingPHID($drydock_phid); - if ($until) { - $lease->setUntil($until); - } + if ($attributes) { + $lease->setAttributes($attributes); + } + + if ($blueprint_phids === null) { + $blueprint_phids = $this->newAllowedBlueprintPHIDs( + $lease, + $filter_blueprints); + } + + $lease->setAllowedBlueprintPHIDs($blueprint_phids); + + if ($until) { + $lease->setUntil($until); + } - // If something fatals or the user interrupts the process (for example, - // with "^C"), release the lease. We'll cancel this below, if the lease - // actually activates. - $lease->setReleaseOnDestruction(true); + // If something fatals or the user interrupts the process (for example, + // with "^C"), release the lease. We'll cancel this below, if the lease + // actually activates. + $lease->setReleaseOnDestruction(true); + + $leases[] = $lease; + } // TODO: This would probably be better handled with PhutilSignalRouter, // but it currently doesn't route SIGINT. We're initializing it to setup @@ -107,29 +133,52 @@ pcntl_signal(SIGINT, array($this, 'didReceiveInterrupt')); $t_start = microtime(true); - $lease->queueForActivation(); + + + echo tsprintf( + "%s\n\n", + pht('Leases queued for activation:')); + + foreach ($leases as $lease) { + $lease->queueForActivation(); + + echo tsprintf( + " __%s__\n", + PhabricatorEnv::getProductionURI($lease->getURI())); + } echo tsprintf( - "%s\n\n __%s__\n\n%s\n", - pht('Queued lease for activation:'), - PhabricatorEnv::getProductionURI($lease->getURI()), - pht('Waiting for daemons to activate lease...')); + "\n%s\n\n", + pht('Waiting for daemons to activate leases...')); - $this->waitUntilActive($lease); + foreach ($leases as $lease) { + $this->waitUntilActive($lease); + } // Now that we've survived activation and the lease is good, make it // durable. - $lease->setReleaseOnDestruction(false); + foreach ($leases as $lease) { + $lease->setReleaseOnDestruction(false); + } + $t_end = microtime(true); echo tsprintf( - "%s\n\n %s\n\n%s\n", + "\n%s\n\n", pht( - 'Activation complete. This lease is permanent until manually '. - 'released with:'), - pht('$ ./bin/drydock release-lease --id %d', $lease->getID()), + 'Activation complete. Leases are permanent until manually '. + 'released with:')); + + foreach ($leases as $lease) { + echo tsprintf( + " %s\n", + pht('$ ./bin/drydock release-lease --id %d', $lease->getID())); + } + + echo tsprintf( + "\n%s\n", pht( - 'Lease activated in %sms.', + 'Leases activated in %sms.', new PhutilNumber((int)(($t_end - $t_start) * 1000)))); return 0; @@ -183,7 +232,8 @@ } echo tsprintf( - "<%s> %B\n", + "(Lease #%d) <%s> %B\n", + $lease->getID(), $type, $data); } @@ -218,4 +268,97 @@ } } + private function getBlueprintFilterMap(array $identifiers) { + $viewer = $this->getViewer(); + + $query = id(new DrydockBlueprintQuery()) + ->setViewer($viewer) + ->withIdentifiers($identifiers); + + $blueprints = $query->execute(); + $blueprints = mpull($blueprints, null, 'getPHID'); + + $map = $query->getIdentifierMap(); + + $seen = array(); + foreach ($identifiers as $identifier) { + if (!isset($map[$identifier])) { + throw new PhutilArgumentUsageException( + pht( + 'Blueprint "%s" could not be loaded. Try a blueprint ID or '. + 'PHID.', + $identifier)); + } + + $blueprint = $map[$identifier]; + + $blueprint_phid = $blueprint->getPHID(); + if (isset($seen[$blueprint_phid])) { + throw new PhutilArgumentUsageException( + pht( + 'Blueprint "%s" is specified more than once (as "%s" and "%s").', + $blueprint->getBlueprintName(), + $seen[$blueprint_phid], + $identifier)); + } + + $seen[$blueprint_phid] = true; + } + + return mpull($map, null, 'getPHID'); + } + + private function newAllowedBlueprintPHIDs( + DrydockLease $lease, + array $filter_blueprints) { + assert_instances_of($filter_blueprints, 'DrydockBlueprint'); + + $viewer = $this->getViewer(); + + $impls = DrydockBlueprintImplementation::getAllForAllocatingLease($lease); + + if (!$impls) { + throw new PhutilArgumentUsageException( + pht( + 'No known blueprint class can ever allocate the specified '. + 'lease. Check that the resource type is spelled correctly.')); + } + + $classes = array_keys($impls); + + $blueprints = id(new DrydockBlueprintQuery()) + ->setViewer($viewer) + ->withBlueprintClasses($classes) + ->withDisabled(false) + ->execute(); + + if (!$blueprints) { + throw new PhutilArgumentUsageException( + pht( + 'No enabled blueprints exist with a blueprint class that can '. + 'plausibly allocate resources to satisfy the requested lease.')); + } + + $phids = mpull($blueprints, 'getPHID'); + + if ($filter_blueprints) { + $allowed_map = array_fuse($phids); + $filter_map = mpull($filter_blueprints, null, 'getPHID'); + + foreach ($filter_map as $filter_phid => $blueprint) { + if (!isset($allowed_map[$filter_phid])) { + throw new PhutilArgumentUsageException( + pht( + 'Specified blueprint "%s" is not capable of satisfying the '. + 'configured lease.', + $blueprint->getBlueprintName())); + } + } + + $phids = mpull($filter_blueprints, 'getPHID'); + } + + return $phids; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,40 +15,71 @@ 'repeat' => true, 'help' => pht('Lease ID to release.'), ), + array( + 'name' => 'all', + 'help' => pht('Release all leases. Dangerous!'), + ), )); } public function execute(PhutilArgumentParser $args) { + $is_all = $args->getArg('all'); $ids = $args->getArg('id'); - if (!$ids) { + + if (!$ids && !$is_all) { throw new PhutilArgumentUsageException( pht( - 'Specify one or more lease IDs to release with "%s".', - '--id')); + 'Select which leases you want to release. See "--help" for '. + 'guidance.')); } $viewer = $this->getViewer(); - $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); - $leases = id(new DrydockLeaseQuery()) + $statuses = $this->getReleaseableLeaseStatuses(); + + $query = id(new DrydockLeaseQuery()) ->setViewer($viewer) - ->withIDs($ids) - ->execute(); + ->withStatuses(mpull($statuses, 'getKey')); - PhabricatorWorker::setRunAllTasksInProcess(true); - foreach ($ids as $id) { - $lease = idx($leases, $id); - if (!$lease) { - echo tsprintf( - "%s\n", - pht('Lease "%s" does not exist.', $id)); - continue; + if ($ids) { + $query->withIDs($ids); + } + + $leases = $query->execute(); + + if ($ids) { + $id_map = mpull($leases, null, 'getID'); + + foreach ($ids as $id) { + $lease = idx($id_map, $id); + if (!$lease) { + throw new PhutilArgumentUsageException( + pht('Lease "%s" does not exist.', $id)); + } } + $leases = array_select_keys($id_map, $ids); + } + + if (!$leases) { + echo tsprintf( + "%s\n", + pht('No leases selected for release.')); + + return 0; + } + + $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); + + PhabricatorWorker::setRunAllTasksInProcess(true); + + foreach ($leases as $lease) { if (!$lease->canRelease()) { echo tsprintf( "%s\n", - pht('Lease "%s" is not releasable.', $id)); + pht( + 'Lease "%s" is not releasable.', + $lease->getDisplayName())); continue; } @@ -62,9 +93,26 @@ echo tsprintf( "%s\n", - pht('Scheduled release of lease "%s".', $id)); + pht( + 'Scheduled release of lease "%s".', + $lease->getDisplayName())); + } + + } + + private function getReleaseableLeaseStatuses() { + $statuses = DrydockLeaseStatus::getAllStatuses(); + foreach ($statuses as $key => $status) { + $statuses[$key] = DrydockLeaseStatus::newStatusObject($status); + } + + foreach ($statuses as $key => $status) { + if (!$status->canRelease()) { + unset($statuses[$key]); + } } + return $statuses; } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,41 +15,70 @@ 'repeat' => true, 'help' => pht('Resource ID to release.'), ), + array( + 'name' => 'all', + 'help' => pht('Release all resources. Dangerous!'), + ), )); } public function execute(PhutilArgumentParser $args) { + $is_all = $args->getArg('all'); $ids = $args->getArg('id'); - if (!$ids) { + if (!$ids && !$is_all) { throw new PhutilArgumentUsageException( pht( - 'Specify one or more resource IDs to release with "%s".', - '--id')); + 'Specify which resources you want to release. See "--help" for '. + 'guidance.')); } $viewer = $this->getViewer(); - $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); + $statuses = $this->getReleaseableResourceStatuses(); - $resources = id(new DrydockResourceQuery()) + $query = id(new DrydockResourceQuery()) ->setViewer($viewer) - ->withIDs($ids) - ->execute(); + ->withStatuses(mpull($statuses, 'getKey')); - PhabricatorWorker::setRunAllTasksInProcess(true); - foreach ($ids as $id) { - $resource = idx($resources, $id); + if ($ids) { + $query->withIDs($ids); + } - if (!$resource) { - echo tsprintf( - "%s\n", - pht('Resource "%s" does not exist.', $id)); - continue; + $resources = $query->execute(); + + if ($ids) { + $id_map = mpull($resources, null, 'getID'); + + foreach ($ids as $id) { + $resource = idx($resources, $id); + + if (!$resource) { + throw new PhutilArgumentUsageException( + pht('Resource "%s" does not exist.', $id)); + } } + $resources = array_select_keys($id_map, $ids); + } + + if (!$resources) { + echo tsprintf( + "%s\n", + pht('No resources selected for release.')); + + return 0; + } + + $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID(); + + PhabricatorWorker::setRunAllTasksInProcess(true); + + foreach ($resources as $resource) { if (!$resource->canRelease()) { echo tsprintf( "%s\n", - pht('Resource "%s" is not releasable.', $id)); + pht( + 'Resource "%s" is not releasable.', + $resource->getDisplayName())); continue; } @@ -63,9 +92,26 @@ echo tsprintf( "%s\n", - pht('Scheduled release of resource "%s".', $id)); + pht( + 'Scheduled release of resource "%s".', + $resource->getDisplayName())); } + return 0; } + private function getReleaseableResourceStatuses() { + $statuses = DrydockResourceStatus::getAllStatuses(); + foreach ($statuses as $key => $status) { + $statuses[$key] = DrydockResourceStatus::newStatusObject($status); + } + + foreach ($statuses as $key => $status) { + if (!$status->canRelease()) { + unset($statuses[$key]); + } + } + + return $statuses; + } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/operation/DrydockLandRepositoryOperation.php phabricator-0~git20220903/phabricator/src/applications/drydock/operation/DrydockLandRepositoryOperation.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/operation/DrydockLandRepositoryOperation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/operation/DrydockLandRepositoryOperation.php 2022-06-14 16:29:55.000000000 +0000 @@ -391,7 +391,7 @@ 'title' => pht('Staging Unavailable'), 'body' => pht( 'When this diff was generated, the server was running an older '. - 'version of Phabricator which did not support staging areas, so '. + 'version of the software which did not support staging areas, so '. 'the change was not pushed to staging. Changes must be pushed '. 'to staging before they can be landed from the web.'), ); @@ -400,7 +400,7 @@ 'title' => pht('Repository Unsupported'), 'body' => pht( 'When this diff was generated, the server was running an older '. - 'version of Phabricator which did not support staging areas for '. + 'version of the software which did not support staging areas for '. 'this version control system, so the change was not pushed to '. 'staging. Changes must be pushed to staging before they can be '. 'landed from the web.'), @@ -432,8 +432,9 @@ 'When this diff was generated, it was not pushed to staging for '. 'an unknown reason (the status code was "%s"). Changes must be '. 'pushed to staging before they can be landed from the web. '. - 'The server may be running an out-of-date version of Phabricator, '. - 'and updating may provide more information about this error.', + 'The server may be running an out-of-date version of this '. + 'software, and updating may provide more information about this '. + 'error.', $status), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockAuthorizationQuery.php phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockAuthorizationQuery.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockAuthorizationQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockAuthorizationQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -72,10 +72,6 @@ return new DrydockAuthorization(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $authorizations) { $blueprint_phids = mpull($authorizations, 'getBlueprintPHID'); if ($blueprint_phids) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockBlueprintQuery.php phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockBlueprintQuery.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockBlueprintQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockBlueprintQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,6 +9,11 @@ private $disabled; private $authorizedPHIDs; + private $identifiers; + private $identifierIDs; + private $identifierPHIDs; + private $identifierMap; + public function withIDs(array $ids) { $this->ids = $ids; return $this; @@ -45,6 +50,43 @@ $ngrams); } + public function withIdentifiers(array $identifiers) { + if (!$identifiers) { + throw new Exception( + pht( + 'Can not issue a query with an empty identifier list.')); + } + + $this->identifiers = $identifiers; + + $ids = array(); + $phids = array(); + + foreach ($identifiers as $identifier) { + if (ctype_digit($identifier)) { + $ids[] = $identifier; + } else { + $phids[] = $identifier; + } + } + + $this->identifierIDs = $ids; + $this->identifierPHIDs = $phids; + + return $this; + } + + public function getIdentifierMap() { + if ($this->identifierMap === null) { + throw new Exception( + pht( + 'Execute a query with identifiers before getting the '. + 'identifier map.')); + } + + return $this->identifierMap; + } + public function newResultObject() { return new DrydockBlueprint(); } @@ -53,8 +95,12 @@ return 'blueprint'; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); + protected function willExecute() { + if ($this->identifiers) { + $this->identifierMap = array(); + } else { + $this->identifierMap = null; + } } protected function willFilterPage(array $blueprints) { @@ -70,6 +116,30 @@ $blueprint->attachImplementation($impl); } + if ($this->identifiers) { + $id_map = mpull($blueprints, null, 'getID'); + $phid_map = mpull($blueprints, null, 'getPHID'); + + $map = $this->identifierMap; + + foreach ($this->identifierIDs as $id) { + if (isset($id_map[$id])) { + $map[$id] = $id_map[$id]; + } + } + + foreach ($this->identifierPHIDs as $phid) { + if (isset($phid_map[$phid])) { + $map[$phid] = $phid_map[$phid]; + } + } + + // Just for consistency, reorder the map to match input order. + $map = array_select_keys($map, $this->identifiers); + + $this->identifierMap = $map; + } + return $blueprints; } @@ -111,6 +181,29 @@ (int)$this->disabled); } + if ($this->identifiers !== null) { + $parts = array(); + + if ($this->identifierIDs) { + $parts[] = qsprintf( + $conn, + 'blueprint.id IN (%Ld)', + $this->identifierIDs); + } + + if ($this->identifierPHIDs) { + $parts[] = qsprintf( + $conn, + 'blueprint.phid IN (%Ls)', + $this->identifierPHIDs); + } + + $where[] = qsprintf( + $conn, + '%LO', + $parts); + } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockCommandQuery.php phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockCommandQuery.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockCommandQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockCommandQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -25,10 +25,6 @@ return new DrydockCommand(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $commands) { $target_phids = mpull($commands, 'getTargetPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockLeaseQuery.php phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockLeaseQuery.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockLeaseQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockLeaseQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,6 +9,8 @@ private $statuses; private $datasourceQuery; private $needUnconsumedCommands; + private $minModified; + private $maxModified; public function withIDs(array $ids) { $this->ids = $ids; @@ -40,6 +42,12 @@ return $this; } + public function withDateModifiedBetween($min_epoch, $max_epoch) { + $this->minModified = $min_epoch; + $this->maxModified = $max_epoch; + return $this; + } + public function needUnconsumedCommands($need) { $this->needUnconsumedCommands = $need; return $this; @@ -49,10 +57,6 @@ return new DrydockLease(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $leases) { $resource_phids = array_filter(mpull($leases, 'getResourcePHID')); if ($resource_phids) { @@ -146,6 +150,20 @@ (int)$this->datasourceQuery); } + if ($this->minModified !== null) { + $where[] = qsprintf( + $conn, + 'dateModified >= %d', + $this->minModified); + } + + if ($this->maxModified !== null) { + $where[] = qsprintf( + $conn, + 'dateModified <= %d', + $this->maxModified); + } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockLogQuery.php phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockLogQuery.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockLogQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockLogQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -37,10 +37,6 @@ return new DrydockLog(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function didFilterPage(array $logs) { $blueprint_phids = array_filter(mpull($logs, 'getBlueprintPHID')); if ($blueprint_phids) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockRepositoryOperationQuery.php phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockRepositoryOperationQuery.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockRepositoryOperationQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockRepositoryOperationQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -55,10 +55,6 @@ return new DrydockRepositoryOperation(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $operations) { $implementations = DrydockRepositoryOperationType::getAllOperationTypes(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockResourceQuery.php phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockResourceQuery.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/query/DrydockResourceQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/query/DrydockResourceQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -49,10 +49,6 @@ return new DrydockResource(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $resources) { $blueprint_phids = mpull($resources, 'getBlueprintPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/storage/DrydockLease.php phabricator-0~git20220903/phabricator/src/applications/drydock/storage/DrydockLease.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/storage/DrydockLease.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/storage/DrydockLease.php 2022-06-14 16:29:55.000000000 +0000 @@ -111,6 +111,9 @@ 'key_owner' => array( 'columns' => array('ownerPHID'), ), + 'key_recent' => array( + 'columns' => array('resourcePHID', 'dateModified'), + ), ), ) + parent::getConfiguration(); } @@ -389,6 +392,62 @@ )); } + public function getAllocatedResourcePHIDs() { + return $this->getAttribute('internal.resourcePHIDs.allocated', array()); + } + + public function setAllocatedResourcePHIDs(array $phids) { + return $this->setAttribute('internal.resourcePHIDs.allocated', $phids); + } + + public function addAllocatedResourcePHIDs(array $phids) { + $allocated_phids = $this->getAllocatedResourcePHIDs(); + + foreach ($phids as $phid) { + $allocated_phids[$phid] = $phid; + } + + return $this->setAllocatedResourcePHIDs($allocated_phids); + } + + public function removeAllocatedResourcePHIDs(array $phids) { + $allocated_phids = $this->getAllocatedResourcePHIDs(); + + foreach ($phids as $phid) { + unset($allocated_phids[$phid]); + } + + return $this->setAllocatedResourcePHIDs($allocated_phids); + } + + public function getReclaimedResourcePHIDs() { + return $this->getAttribute('internal.resourcePHIDs.reclaimed', array()); + } + + public function setReclaimedResourcePHIDs(array $phids) { + return $this->setAttribute('internal.resourcePHIDs.reclaimed', $phids); + } + + public function addReclaimedResourcePHIDs(array $phids) { + $reclaimed_phids = $this->getReclaimedResourcePHIDs(); + + foreach ($phids as $phid) { + $reclaimed_phids[$phid] = $phid; + } + + return $this->setReclaimedResourcePHIDs($reclaimed_phids); + } + + public function removeReclaimedResourcePHIDs(array $phids) { + $reclaimed_phids = $this->getReclaimedResourcePHIDs(); + + foreach ($phids as $phid) { + unset($reclaimed_phids[$phid]); + } + + return $this->setReclaimedResourcePHIDs($reclaimed_phids); + } + public function setAwakenTaskIDs(array $ids) { $this->setAttribute('internal.awakenTaskIDs', $ids); return $this; @@ -468,6 +527,10 @@ return "/drydock/lease/{$id}/"; } + public function getDisplayName() { + return pht('Drydock Lease %d', $this->getID()); + } + /* -( Status )------------------------------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/storage/DrydockResource.php phabricator-0~git20220903/phabricator/src/applications/drydock/storage/DrydockResource.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/storage/DrydockResource.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/storage/DrydockResource.php 2022-06-14 16:29:55.000000000 +0000 @@ -286,6 +286,10 @@ return $log->save(); } + public function getDisplayName() { + return pht('Drydock Resource %d', $this->getID()); + } + /* -( Status )------------------------------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php phabricator-0~git20220903/phabricator/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -188,137 +188,361 @@ // First, try to find a suitable open resource which we can acquire a new // lease on. - $resources = $this->loadResourcesForAllocatingLease($blueprints, $lease); + $resources = $this->loadAcquirableResourcesForLease($blueprints, $lease); - // If no resources exist yet, see if we can build one. - if (!$resources) { - $usable_blueprints = $this->removeOverallocatedBlueprints( - $blueprints, - $lease); - - // If we get nothing back here, some blueprint claims it can eventually - // satisfy the lease, just not right now. This is a temporary failure, - // and we expect allocation to succeed eventually. - if (!$usable_blueprints) { - $blueprints = $this->rankBlueprints($blueprints, $lease); - - // Try to actively reclaim unused resources. If we succeed, jump back - // into the queue in an effort to claim it. - foreach ($blueprints as $blueprint) { - $reclaimed = $this->reclaimResources($blueprint, $lease); - if ($reclaimed) { - $lease->logEvent( - DrydockLeaseReclaimLogType::LOGCONST, - array( - 'resourcePHIDs' => array($reclaimed->getPHID()), - )); + list($free_resources, $used_resources) = $this->partitionResources( + $lease, + $resources); - throw new PhabricatorWorkerYieldException(15); - } - } + $resource = $this->leaseAnyResource($lease, $free_resources); + if ($resource) { + return $resource; + } + + // We're about to try creating a resource. If we're already creating + // something, just yield until that resolves. + + $this->yieldForPendingResources($lease); + + // We haven't been able to lease an existing resource yet, so now we try to + // create one. We may still have some less-desirable "used" resources that + // we'll sometimes try to lease later if we fail to allocate a new resource. + + $resource = $this->newLeasedResource($lease, $blueprints); + if ($resource) { + return $resource; + } + + // We haven't been able to lease a desirable "free" resource or create a + // new resource. Try to lease a "used" resource. + + $resource = $this->leaseAnyResource($lease, $used_resources); + if ($resource) { + return $resource; + } + + // If this lease has already triggered a reclaim, just yield and wait for + // it to resolve. + $this->yieldForReclaimingResources($lease); + + // Try to reclaim a resource. This will yield if it reclaims something. + $this->reclaimAnyResource($lease, $blueprints); + + // We weren't able to lease, create, or reclaim any resources. We just have + // to wait for resources to become available. + + $lease->logEvent( + DrydockLeaseWaitingForResourcesLogType::LOGCONST, + array( + 'blueprintPHIDs' => mpull($blueprints, 'getPHID'), + )); + + throw new PhabricatorWorkerYieldException(15); + } + + private function reclaimAnyResource(DrydockLease $lease, array $blueprints) { + assert_instances_of($blueprints, 'DrydockBlueprint'); + + $blueprints = $this->rankBlueprints($blueprints, $lease); + + // Try to actively reclaim unused resources. If we succeed, jump back + // into the queue in an effort to claim it. + + foreach ($blueprints as $blueprint) { + $reclaimed = $this->reclaimResources($blueprint, $lease); + if ($reclaimed) { $lease->logEvent( - DrydockLeaseWaitingForResourcesLogType::LOGCONST, + DrydockLeaseReclaimLogType::LOGCONST, array( - 'blueprintPHIDs' => mpull($blueprints, 'getPHID'), + 'resourcePHIDs' => array($reclaimed->getPHID()), )); + // Yield explicitly here: we'll be awakened when the resource is + // reclaimed. + throw new PhabricatorWorkerYieldException(15); } + } + } - $usable_blueprints = $this->rankBlueprints($usable_blueprints, $lease); + private function yieldForPendingResources(DrydockLease $lease) { + // See T13677. If this lease has already triggered the allocation of + // one or more resources and they are still pending, just yield and + // wait for them. - $exceptions = array(); - foreach ($usable_blueprints as $blueprint) { - try { - $resources[] = $this->allocateResource($blueprint, $lease); - - // Bail after allocating one resource, we don't need any more than - // this. - break; - } catch (Exception $ex) { - // This failure is not normally expected, so log it. It can be - // caused by something mundane and recoverable, however (see below - // for discussion). - - // We log to the blueprint separately from the log to the lease: - // the lease is not attached to a blueprint yet so the lease log - // will not show up on the blueprint; more than one blueprint may - // fail; and the lease is not really impacted (and won't log) if at - // least one blueprint actually works. + $viewer = $this->getViewer(); - $blueprint->logEvent( - DrydockResourceAllocationFailureLogType::LOGCONST, - array( - 'class' => get_class($ex), - 'message' => $ex->getMessage(), - )); + $phids = $lease->getAllocatedResourcePHIDs(); + if (!$phids) { + return null; + } - $exceptions[] = $ex; - } + $resources = id(new DrydockResourceQuery()) + ->setViewer($viewer) + ->withPHIDs($phids) + ->withStatuses( + array( + DrydockResourceStatus::STATUS_PENDING, + )) + ->setLimit(1) + ->execute(); + if (!$resources) { + return; + } + + $lease->logEvent( + DrydockLeaseWaitingForActivationLogType::LOGCONST, + array( + 'resourcePHIDs' => mpull($resources, 'getPHID'), + )); + + throw new PhabricatorWorkerYieldException(15); + } + + private function yieldForReclaimingResources(DrydockLease $lease) { + $viewer = $this->getViewer(); + + $phids = $lease->getReclaimedResourcePHIDs(); + if (!$phids) { + return; + } + + $resources = id(new DrydockResourceQuery()) + ->setViewer($viewer) + ->withPHIDs($phids) + ->withStatuses( + array( + DrydockResourceStatus::STATUS_ACTIVE, + DrydockResourceStatus::STATUS_RELEASED, + )) + ->setLimit(1) + ->execute(); + if (!$resources) { + return; + } + + $lease->logEvent( + DrydockLeaseWaitingForReclamationLogType::LOGCONST, + array( + 'resourcePHIDs' => mpull($resources, 'getPHID'), + )); + + throw new PhabricatorWorkerYieldException(15); + } + + private function newLeasedResource( + DrydockLease $lease, + array $blueprints) { + assert_instances_of($blueprints, 'DrydockBlueprint'); + + $usable_blueprints = $this->removeOverallocatedBlueprints( + $blueprints, + $lease); + + // If we get nothing back here, some blueprint claims it can eventually + // satisfy the lease, just not right now. This is a temporary failure, + // and we expect allocation to succeed eventually. + + // Return, try to lease a "used" resource, and continue from there. + + if (!$usable_blueprints) { + return null; + } + + $usable_blueprints = $this->rankBlueprints($usable_blueprints, $lease); + + $new_resources = $this->newResources($lease, $usable_blueprints); + if (!$new_resources) { + // If we were unable to create any new resources, return and + // try to lease a "used" resource. + return null; + } + + $new_resources = $this->removeUnacquirableResources( + $new_resources, + $lease); + if (!$new_resources) { + // If we make it here, we just built a resource but aren't allowed + // to acquire it. We expect this to happen if the resource prevents + // acquisition until it activates, which is common when a resource + // needs to perform setup steps. + + // Explicitly yield and wait for activation, since we don't want to + // lease a "used" resource. + + throw new PhabricatorWorkerYieldException(15); + } + + $resource = $this->leaseAnyResource($lease, $new_resources); + if ($resource) { + return $resource; + } + + // We may not be able to lease a resource even if we just built it: + // another process may snatch it up before we can lease it. This should + // be rare, but is not concerning. Just try to build another resource. + + // We likely could try to build the next resource immediately, but err on + // the side of caution and yield for now, at least until this code is + // better vetted. + + throw new PhabricatorWorkerYieldException(15); + } + + private function partitionResources( + DrydockLease $lease, + array $resources) { + + assert_instances_of($resources, 'DrydockResource'); + $viewer = $this->getViewer(); + + $lease_statuses = array( + DrydockLeaseStatus::STATUS_PENDING, + DrydockLeaseStatus::STATUS_ACQUIRED, + DrydockLeaseStatus::STATUS_ACTIVE, + ); + + // Partition resources into "free" resources (which we can try to lease + // immediately) and "used" resources, which we can only to lease after we + // fail to allocate a new resource. + + // "Free" resources are unleased and/or prefer reuse over allocation. + // "Used" resources are leased and prefer allocation over reuse. + + $free_resources = array(); + $used_resources = array(); + + foreach ($resources as $resource) { + $blueprint = $resource->getBlueprint(); + + if (!$blueprint->shouldAllocateSupplementalResource($resource, $lease)) { + $free_resources[] = $resource; + continue; } - if (!$resources) { - // If one or more blueprints claimed that they would be able to - // allocate resources but none are actually able to allocate resources, - // log the failure and yield so we try again soon. - - // This can happen if some unexpected issue occurs during allocation - // (for example, a call to build a VM fails for some reason) or if we - // raced another allocator and the blueprint is now full. - - $ex = new PhutilAggregateException( - pht( - 'All blueprints failed to allocate a suitable new resource when '. - 'trying to allocate lease ("%s").', - $lease->getPHID()), - $exceptions); + $leases = id(new DrydockLeaseQuery()) + ->setViewer($viewer) + ->withResourcePHIDs(array($resource->getPHID())) + ->withStatuses($lease_statuses) + ->setLimit(1) + ->execute(); + if (!$leases) { + $free_resources[] = $resource; + continue; + } - $lease->logEvent( - DrydockLeaseAllocationFailureLogType::LOGCONST, + $used_resources[] = $resource; + } + + return array($free_resources, $used_resources); + } + + private function newResources( + DrydockLease $lease, + array $blueprints) { + assert_instances_of($blueprints, 'DrydockBlueprint'); + + $resources = array(); + $exceptions = array(); + foreach ($blueprints as $blueprint) { + $caught = null; + try { + $resources[] = $this->allocateResource($blueprint, $lease); + + // Bail after allocating one resource, we don't need any more than + // this. + break; + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + if ($caught) { + // This failure is not normally expected, so log it. It can be + // caused by something mundane and recoverable, however (see below + // for discussion). + + // We log to the blueprint separately from the log to the lease: + // the lease is not attached to a blueprint yet so the lease log + // will not show up on the blueprint; more than one blueprint may + // fail; and the lease is not really impacted (and won't log) if at + // least one blueprint actually works. + + $blueprint->logEvent( + DrydockResourceAllocationFailureLogType::LOGCONST, array( - 'class' => get_class($ex), - 'message' => $ex->getMessage(), + 'class' => get_class($caught), + 'message' => $caught->getMessage(), )); - throw new PhabricatorWorkerYieldException(15); + $exceptions[] = $caught; } + } - $resources = $this->removeUnacquirableResources($resources, $lease); - if (!$resources) { - // If we make it here, we just built a resource but aren't allowed - // to acquire it. We expect this during routine operation if the - // resource prevents acquisition until it activates. Yield and wait - // for activation. - throw new PhabricatorWorkerYieldException(15); - } + if (!$resources) { + // If one or more blueprints claimed that they would be able to allocate + // resources but none are actually able to allocate resources, log the + // failure and yield so we try again soon. + + // This can happen if some unexpected issue occurs during allocation + // (for example, a call to build a VM fails for some reason) or if we + // raced another allocator and the blueprint is now full. + + $ex = new PhutilAggregateException( + pht( + 'All blueprints failed to allocate a suitable new resource when '. + 'trying to allocate lease ("%s").', + $lease->getPHID()), + $exceptions); + + $lease->logEvent( + DrydockLeaseAllocationFailureLogType::LOGCONST, + array( + 'class' => get_class($ex), + 'message' => $ex->getMessage(), + )); - // NOTE: We have not acquired the lease yet, so it is possible that the - // resource we just built will be snatched up by some other lease before - // we can acquire it. This is not problematic: we'll retry a little later - // and should succeed eventually. + return null; + } + + return $resources; + } + + + private function leaseAnyResource( + DrydockLease $lease, + array $resources) { + assert_instances_of($resources, 'DrydockResource'); + + if (!$resources) { + return null; } $resources = $this->rankResources($resources, $lease); $exceptions = array(); $yields = array(); - $allocated = false; + + $allocated = null; foreach ($resources as $resource) { try { - $resource = $this->newResourceForAcquisition($resource, $lease); $this->acquireLease($resource, $lease); - $allocated = true; + $allocated = $resource; break; } catch (DrydockResourceLockException $ex) { // We need to lock the resource to actually acquire it. If we aren't // able to acquire the lock quickly enough, we can yield and try again // later. $yields[] = $ex; + } catch (DrydockSlotLockException $ex) { + // This also just indicates we ran into some kind of contention, + // probably from another lease. Just yield. + $yields[] = $ex; } catch (DrydockAcquiredBrokenResourceException $ex) { // If a resource was reclaimed or destroyed by the time we actually - // got around to acquiring it, we just got unlucky. We can yield and - // try again later. + // got around to acquiring it, we just got unlucky. $yields[] = $ex; } catch (PhabricatorWorkerYieldException $ex) { // We can be told to yield, particularly by the supplemental allocator @@ -329,59 +553,19 @@ } } - if (!$allocated) { - if ($yields) { - throw new PhabricatorWorkerYieldException(15); - } else { - throw new PhutilAggregateException( - pht( - 'Unable to acquire lease "%s" on any resource.', - $lease->getPHID()), - $exceptions); - } + if ($allocated) { + return $allocated; } - } - - /** - * Get all the @{class:DrydockBlueprintImplementation}s which can possibly - * build a resource to satisfy a lease. - * - * This method returns blueprints which might, at some time, be able to - * build a resource which can satisfy the lease. They may not be able to - * build that resource right now. - * - * @param DrydockLease Requested lease. - * @return list<DrydockBlueprintImplementation> List of qualifying blueprint - * implementations. - * @task allocator - */ - private function loadBlueprintImplementationsForAllocatingLease( - DrydockLease $lease) { - - $impls = DrydockBlueprintImplementation::getAllBlueprintImplementations(); - - $keep = array(); - foreach ($impls as $key => $impl) { - // Don't use disabled blueprint types. - if (!$impl->isEnabled()) { - continue; - } - - // Don't use blueprint types which can't allocate the correct kind of - // resource. - if ($impl->getType() != $lease->getResourceType()) { - continue; - } - - if (!$impl->canAnyBlueprintEverAllocateResourceForLease($lease)) { - continue; - } - - $keep[$key] = $impl; + if ($yields) { + throw new PhabricatorWorkerYieldException(15); } - return $keep; + throw new PhutilAggregateException( + pht( + 'Unable to acquire lease "%s" on any resource.', + $lease->getPHID()), + $exceptions); } @@ -397,7 +581,7 @@ DrydockLease $lease) { $viewer = $this->getViewer(); - $impls = $this->loadBlueprintImplementationsForAllocatingLease($lease); + $impls = DrydockBlueprintImplementation::getAllForAllocatingLease($lease); if (!$impls) { return array(); } @@ -468,7 +652,7 @@ * the lease. * @task allocator */ - private function loadResourcesForAllocatingLease( + private function loadAcquirableResourcesForLease( array $blueprints, DrydockLease $lease) { assert_instances_of($blueprints, 'DrydockBlueprint'); @@ -480,7 +664,6 @@ ->withTypes(array($lease->getResourceType())) ->withStatuses( array( - DrydockResourceStatus::STATUS_PENDING, DrydockResourceStatus::STATUS_ACTIVE, )) ->execute(); @@ -600,6 +783,13 @@ // If this resource was allocated as a pending resource, queue a task to // activate it. if ($resource->getStatus() == DrydockResourceStatus::STATUS_PENDING) { + + $lease->addAllocatedResourcePHIDs( + array( + $resource->getPHID(), + )); + $lease->save(); + PhabricatorWorker::scheduleTask( 'DrydockResourceUpdateWorker', array( @@ -678,26 +868,6 @@ DrydockLease $lease) { $viewer = $this->getViewer(); - // If this lease is marked as already in the process of reclaiming a - // resource, don't let it reclaim another one until the first reclaim - // completes. This stops one lease from reclaiming a large number of - // resources if the reclaims take a while to complete. - $reclaiming_phid = $lease->getAttribute('drydock.reclaimingPHID'); - if ($reclaiming_phid) { - $reclaiming_resource = id(new DrydockResourceQuery()) - ->setViewer($viewer) - ->withPHIDs(array($reclaiming_phid)) - ->withStatuses( - array( - DrydockResourceStatus::STATUS_ACTIVE, - DrydockResourceStatus::STATUS_RELEASED, - )) - ->executeOne(); - if ($reclaiming_resource) { - return null; - } - } - $resources = id(new DrydockResourceQuery()) ->setViewer($viewer) ->withBlueprintPHIDs(array($blueprint->getPHID())) @@ -796,73 +966,6 @@ } } - private function newResourceForAcquisition( - DrydockResource $resource, - DrydockLease $lease) { - - // If the resource has no leases against it, never build a new one. This is - // likely already a new resource that just activated. - $viewer = $this->getViewer(); - - $statuses = array( - DrydockLeaseStatus::STATUS_PENDING, - DrydockLeaseStatus::STATUS_ACQUIRED, - DrydockLeaseStatus::STATUS_ACTIVE, - ); - - $leases = id(new DrydockLeaseQuery()) - ->setViewer($viewer) - ->withResourcePHIDs(array($resource->getPHID())) - ->withStatuses($statuses) - ->setLimit(1) - ->execute(); - if (!$leases) { - return $resource; - } - - // If we're about to get a lease on a resource, check if the blueprint - // wants to allocate a supplemental resource. If it does, try to perform a - // new allocation instead. - $blueprint = $resource->getBlueprint(); - if (!$blueprint->shouldAllocateSupplementalResource($resource, $lease)) { - return $resource; - } - - // If the blueprint is already overallocated, we can't allocate a new - // resource. Just return the existing resource. - $remaining = $this->removeOverallocatedBlueprints( - array($blueprint), - $lease); - if (!$remaining) { - return $resource; - } - - // Try to build a new resource. - try { - $new_resource = $this->allocateResource($blueprint, $lease); - } catch (Exception $ex) { - $blueprint->logEvent( - DrydockResourceAllocationFailureLogType::LOGCONST, - array( - 'class' => get_class($ex), - 'message' => $ex->getMessage(), - )); - - return $resource; - } - - // If we can't actually acquire the new resource yet, just yield. - // (We could try to move forward with the original resource instead.) - $acquirable = $this->removeUnacquirableResources( - array($new_resource), - $lease); - if (!$acquirable) { - throw new PhabricatorWorkerYieldException(15); - } - - return $new_resource; - } - /* -( Activating Leases )-------------------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/drydock/worker/DrydockWorker.php phabricator-0~git20220903/phabricator/src/applications/drydock/worker/DrydockWorker.php --- phabricator-0~git20200925/phabricator/src/applications/drydock/worker/DrydockWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/drydock/worker/DrydockWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -203,14 +203,15 @@ // from one another forever without making progress, so make resources // immune to reclamation for a little while after they activate or update. + $now = PhabricatorTime::getNow(); + $max_epoch = ($now - phutil_units('3 minutes in seconds')); + // TODO: It would be nice to use a more narrow time here, like "last // activation or lease release", but we don't currently store that // anywhere. $updated = $resource->getDateModified(); - $now = PhabricatorTime::getNow(); - $ago = ($now - $updated); - if ($ago < phutil_units('3 minutes in seconds')) { + if ($updated > $max_epoch) { return false; } @@ -233,6 +234,21 @@ return false; } + // See T13676. Don't reclaim a resource if a lease recently released. + $leases = id(new DrydockLeaseQuery()) + ->setViewer($viewer) + ->withResourcePHIDs(array($resource->getPHID())) + ->withStatuses( + array( + DrydockLeaseStatus::STATUS_DESTROYED, + )) + ->withDateModifiedBetween($max_epoch, null) + ->setLimit(1) + ->execute(); + if ($leases) { + return false; + } + return true; } @@ -244,7 +260,7 @@ // Mark the lease as reclaiming this resource. It won't be allowed to start // another reclaim as long as this resource is still in the process of // being reclaimed. - $lease->setAttribute('drydock.reclaimingPHID', $resource->getPHID()); + $lease->addReclaimedResourcePHIDs(array($resource->getPHID())); // When the resource releases, we we want to reawaken this task since it // should (usually) be able to start building a new resource right away. diff -Nru phabricator-0~git20200925/phabricator/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/feed/conduit/FeedPublishConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -<?php - -final class FeedPublishConduitAPIMethod extends FeedConduitAPIMethod { - - public function getAPIMethodName() { - return 'feed.publish'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht('Publish a story to the feed.'); - } - - protected function defineParamTypes() { - return array( - 'type' => 'required string', - 'data' => 'required dict', - 'time' => 'optional int', - ); - } - - protected function defineReturnType() { - return 'nonempty phid'; - } - - protected function execute(ConduitAPIRequest $request) { - $type = $request->getValue('type'); - $data = $request->getValue('data'); - $time = $request->getValue('time'); - - $author_phid = $request->getUser()->getPHID(); - $phids = array($author_phid); - - $publisher = new PhabricatorFeedStoryPublisher(); - $publisher->setStoryType($type); - $publisher->setStoryData($data); - $publisher->setStoryTime($time); - $publisher->setRelatedPHIDs($phids); - $publisher->setStoryAuthorPHID($author_phid); - - $data = $publisher->publish(); - - return $data->getPHID(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/feed/config/PhabricatorFeedConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/feed/config/PhabricatorFeedConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/feed/config/PhabricatorFeedConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/feed/config/PhabricatorFeedConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -24,7 +24,7 @@ IMPORTANT: Feed hooks are deprecated and have been replaced by Webhooks. You can configure Webhooks in Herald. This configuration option will be removed -in a future version of Phabricator. +in a future version of the software. (This legacy option may be configured with a list of URIs; feed stories will send to these URIs.) diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/application/PhabricatorFilesApplication.php phabricator-0~git20220903/phabricator/src/applications/files/application/PhabricatorFilesApplication.php --- phabricator-0~git20200925/phabricator/src/applications/files/application/PhabricatorFilesApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/application/PhabricatorFilesApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -95,6 +95,16 @@ ), 'document/(?P<engineKey>[^/]+)/(?P<phid>[^/]+)/' => 'PhabricatorFileDocumentController', + 'ui/' => array( + 'detach/(?P<objectPHID>[^/]+)/(?P<filePHID>[^/]+)/' + => 'PhabricatorFileDetachController', + 'curtain/' => array( + 'list/(?P<phid>[^/]+)/' + => 'PhabricatorFileUICurtainListController', + 'attach/(?P<objectPHID>[^/]+)/(?P<filePHID>[^/]+)/' + => 'PhabricatorFileUICurtainAttachController', + ), + ), ) + $this->getResourceSubroutes(), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/config/PhabricatorFilesConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/files/config/PhabricatorFilesConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/files/config/PhabricatorFilesConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/config/PhabricatorFilesConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -181,7 +181,7 @@ ->setSummary(pht('Local storage disk path.')) ->setDescription( pht( - "Phabricator provides a local disk storage engine, which just ". + "This software provides a local disk storage engine, which just ". "writes files to some directory on local disk. The webserver ". "must have read/write permissions on this directory. This is ". "straightforward and suitable for most installs, but will not ". diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileDetachController.php phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileDetachController.php --- phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileDetachController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileDetachController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,120 @@ +<?php + +final class PhabricatorFileDetachController + extends PhabricatorFileController { + + public function handleRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); + + $object_phid = $request->getURIData('objectPHID'); + $file_phid = $request->getURIData('filePHID'); + + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($object_phid)) + ->executeOne(); + if (!$object) { + return new Aphront404Response(); + } + + $handles = $viewer->loadHandles( + array( + $object_phid, + $file_phid, + )); + + $object_handle = $handles[$object_phid]; + $file_handle = $handles[$file_phid]; + $cancel_uri = $file_handle->getURI(); + + $dialog = $this->newDialog() + ->setViewer($viewer) + ->setTitle(pht('Detach File')) + ->addCancelButton($cancel_uri, pht('Close')); + + $file_link = phutil_tag('strong', array(), $file_handle->renderLink()); + $object_link = phutil_tag('strong', array(), $object_handle->renderLink()); + + $attachment = id(new PhabricatorFileAttachmentQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($object->getPHID())) + ->withFilePHIDs(array($file_phid)) + ->needFiles(true) + ->withVisibleFiles(true) + ->executeOne(); + if (!$attachment) { + $body = pht( + 'The file %s is not attached to the object %s.', + $file_link, + $object_link); + + return $dialog->appendParagraph($body); + } + + $mode_reference = PhabricatorFileAttachment::MODE_REFERENCE; + if ($attachment->getAttachmentMode() === $mode_reference) { + $body = pht( + 'The file %s is referenced by the object %s, but not attached to '. + 'it, so it can not be detached.', + $file_link, + $object_link); + + return $dialog->appendParagraph($body); + } + + if (!$attachment->canDetach()) { + $body = pht( + 'The file %s can not be detached from the object %s.', + $file_link, + $object_link); + + return $dialog->appendParagraph($body); + } + + if (!$request->isDialogFormPost()) { + $dialog->appendParagraph( + pht( + 'Detach the file %s from the object %s?', + $file_link, + $object_link)); + + $dialog->addSubmitButton(pht('Detach File')); + + return $dialog; + } + + if (!($object instanceof PhabricatorApplicationTransactionInterface)) { + $dialog->appendParagraph( + pht( + 'This object (of class "%s") does not implement the required '. + 'interface ("%s"), so files can not be manually detached from it.', + get_class($object), + 'PhabricatorApplicationTransactionInterface')); + + return $dialog; + } + + $editor = $object->getApplicationTransactionEditor() + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); + + $template = $object->getApplicationTransactionTemplate(); + + $xactions = array(); + + $xactions[] = id(clone $template) + ->setTransactionType(PhabricatorTransactions::TYPE_FILE) + ->setNewValue( + array( + $file_phid => PhabricatorFileAttachment::MODE_DETACH, + )); + + $editor->applyTransactions($object, $xactions); + + return $this->newRedirect() + ->setURI($cancel_uri); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileUICurtainAttachController.php phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileUICurtainAttachController.php --- phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileUICurtainAttachController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileUICurtainAttachController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,133 @@ +<?php + +final class PhabricatorFileUICurtainAttachController + extends PhabricatorFileController { + + public function handleRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); + + $object_phid = $request->getURIData('objectPHID'); + $file_phid = $request->getURIData('filePHID'); + + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($object_phid)) + ->executeOne(); + if (!$object) { + return new Aphront404Response(); + } + + $attachment = id(new PhabricatorFileAttachmentQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($object->getPHID())) + ->withFilePHIDs(array($file_phid)) + ->needFiles(true) + ->withVisibleFiles(true) + ->executeOne(); + if (!$attachment) { + return new Aphront404Response(); + } + + $handles = $viewer->loadHandles( + array( + $object_phid, + $file_phid, + )); + + $object_handle = $handles[$object_phid]; + $file_handle = $handles[$file_phid]; + $cancel_uri = $object_handle->getURI(); + + $dialog = $this->newDialog() + ->setViewer($viewer) + ->setTitle(pht('Attach File')) + ->addCancelButton($cancel_uri, pht('Close')); + + $file_link = phutil_tag('strong', array(), $file_handle->renderLink()); + $object_link = phutil_tag('strong', array(), $object_handle->renderLink()); + + if ($attachment->isPolicyAttachment()) { + $body = pht( + 'The file %s is already attached to the object %s.', + $file_link, + $object_link); + + return $dialog->appendParagraph($body); + } + + if (!$request->isDialogFormPost()) { + $dialog->appendRemarkup( + pht( + '(WARNING) This file is referenced by this object, but '. + 'not formally attached to it. Users who can see the object may '. + 'not be able to see the file.')); + + $dialog->appendParagraph( + pht( + 'Do you want to attach the file %s to the object %s?', + $file_link, + $object_link)); + + $dialog->addSubmitButton(pht('Attach File')); + + return $dialog; + } + + if (!$request->getBool('confirm')) { + $dialog->setTitle(pht('Confirm File Attachment')); + + $dialog->addHiddenInput('confirm', 1); + + $dialog->appendRemarkup( + pht( + '(IMPORTANT) If you attach this file to this object, any user who '. + 'has permission to view the object will be able to view and '. + 'download the file!')); + + $dialog->appendParagraph( + pht( + 'Really attach the file %s to the object %s, allowing any user '. + 'who can view the object to view and download the file?', + $file_link, + $object_link)); + + $dialog->addSubmitButton(pht('Grant Permission')); + + return $dialog; + } + + if (!($object instanceof PhabricatorApplicationTransactionInterface)) { + $dialog->appendParagraph( + pht( + 'This object (of class "%s") does not implement the required '. + 'interface ("%s"), so files can not be manually attached to it.', + get_class($object), + 'PhabricatorApplicationTransactionInterface')); + + return $dialog; + } + + $editor = $object->getApplicationTransactionEditor() + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); + + $template = $object->getApplicationTransactionTemplate(); + + $xactions = array(); + + $xactions[] = id(clone $template) + ->setTransactionType(PhabricatorTransactions::TYPE_FILE) + ->setNewValue( + array( + $file_phid => PhabricatorFileAttachment::MODE_ATTACH, + )); + + $editor->applyTransactions($object, $xactions); + + return $this->newRedirect() + ->setURI($cancel_uri); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileUICurtainListController.php phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileUICurtainListController.php --- phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileUICurtainListController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileUICurtainListController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,61 @@ +<?php + +final class PhabricatorFileUICurtainListController + extends PhabricatorFileController { + + public function shouldAllowPublic() { + return true; + } + + public function handleRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); + + $object_phid = $request->getURIData('phid'); + + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($object_phid)) + ->executeOne(); + if (!$object) { + return new Aphront404Response(); + } + + $attachments = id(new PhabricatorFileAttachmentQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($object->getPHID())) + ->needFiles(true) + ->execute(); + + $handles = $viewer->loadHandles(array($object_phid)); + $object_handle = $handles[$object_phid]; + + $file_phids = mpull($attachments, 'getFilePHID'); + $file_handles = $viewer->loadHandles($file_phids); + + $list = id(new PHUIObjectItemListView()) + ->setUser($viewer); + foreach ($attachments as $attachment) { + $file_phid = $attachment->getFilePHID(); + $handle = $file_handles[$file_phid]; + + $item = id(new PHUIObjectItemView()) + ->setHeader($handle->getFullName()) + ->setHref($handle->getURI()) + ->setDisabled($handle->isDisabled()); + + if ($handle->getImageURI()) { + $item->setImageURI($handle->getImageURI()); + } + + $list->addItem($item); + } + + return $this->newDialog() + ->setViewer($viewer) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->setTitle(pht('Referenced Files')) + ->setObjectList($list) + ->addCancelButton($object_handle->getURI(), pht('Close')); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileUploadController.php phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileUploadController.php --- phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileUploadController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileUploadController.php 2022-06-14 16:29:55.000000000 +0000 @@ -46,7 +46,7 @@ pht('Drag and Drop:'), pht( 'You can also upload files by dragging and dropping them from your '. - 'desktop onto this page or the Phabricator home page.'))); + 'desktop onto this page or the home page.'))); $policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileViewController.php phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileViewController.php --- phabricator-0~git20200925/phabricator/src/applications/files/controller/PhabricatorFileViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/controller/PhabricatorFileViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -310,22 +310,24 @@ pht('Storage Handle'), $file->getStorageHandle()); + $custom_alt = $file->getCustomAltText(); + if (strlen($custom_alt)) { + $finfo->addProperty(pht('Custom Alt Text'), $custom_alt); + } - $phids = $file->getObjectPHIDs(); - if ($phids) { - $attached = new PHUIPropertyListView(); - - $tab_group->addTab( - id(new PHUITabView()) - ->setName(pht('Attached')) - ->setKey('attached') - ->appendChild($attached)); - - $attached->addProperty( - pht('Attached To'), - $viewer->renderHandleList($phids)); + $default_alt = $file->getDefaultAltText(); + if (strlen($default_alt)) { + $finfo->addProperty(pht('Default Alt Text'), $default_alt); } + $attachments_table = $this->newAttachmentsView($file); + + $tab_group->addTab( + id(new PHUITabView()) + ->setName(pht('Attached')) + ->setKey('attached') + ->appendChild($attachments_table)); + $engine = $this->loadStorageEngine($file); if ($engine) { if ($engine->isChunkEngine()) { @@ -411,4 +413,81 @@ return $engine->newDocumentView($ref); } + private function newAttachmentsView(PhabricatorFile $file) { + $viewer = $this->getViewer(); + + $attachments = id(new PhabricatorFileAttachmentQuery()) + ->setViewer($viewer) + ->withFilePHIDs(array($file->getPHID())) + ->execute(); + + $handles = $viewer->loadHandles(mpull($attachments, 'getObjectPHID')); + + $rows = array(); + + $mode_map = PhabricatorFileAttachment::getModeNameMap(); + $mode_attach = PhabricatorFileAttachment::MODE_ATTACH; + + foreach ($attachments as $attachment) { + $object_phid = $attachment->getObjectPHID(); + $handle = $handles[$object_phid]; + + $attachment_mode = $attachment->getAttachmentMode(); + + $mode_name = idx($mode_map, $attachment_mode); + if ($mode_name === null) { + $mode_name = pht('Unknown ("%s")', $attachment_mode); + } + + $detach_uri = urisprintf( + '/file/ui/detach/%s/%s/', + $object_phid, + $file->getPHID()); + + $is_disabled = !$attachment->canDetach(); + + $detach_button = id(new PHUIButtonView()) + ->setHref($detach_uri) + ->setTag('a') + ->setWorkflow(true) + ->setDisabled($is_disabled) + ->setColor(PHUIButtonView::GREY) + ->setSize(PHUIButtonView::SMALL) + ->setText(pht('Detach File')); + + javelin_tag( + 'a', + array( + 'href' => $detach_uri, + 'sigil' => 'workflow', + 'disabled' => true, + 'class' => 'small button button-grey disabled', + ), + pht('Detach File')); + + $rows[] = array( + $handle->renderLink(), + $mode_name, + $detach_button, + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('Attached To'), + pht('Mode'), + null, + )) + ->setColumnClasses( + array( + 'pri wide', + null, + null, + )); + + return $table; + } + + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/document/exception/PhabricatorDocumentEngineParserException.php phabricator-0~git20220903/phabricator/src/applications/files/document/exception/PhabricatorDocumentEngineParserException.php --- phabricator-0~git20200925/phabricator/src/applications/files/document/exception/PhabricatorDocumentEngineParserException.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/document/exception/PhabricatorDocumentEngineParserException.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,4 @@ +<?php + +final class PhabricatorDocumentEngineParserException + extends Exception {} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorDocumentRef.php phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorDocumentRef.php --- phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorDocumentRef.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorDocumentRef.php 2022-06-14 16:29:55.000000000 +0000 @@ -112,6 +112,11 @@ public function hasAnyMimeType(array $candidate_types) { $mime_full = $this->getMimeType(); + + if (!phutil_nonempty_string($mime_full)) { + return false; + } + $mime_parts = explode(';', $mime_full); $mime_type = head($mime_parts); diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorImageDocumentEngine.php phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorImageDocumentEngine.php --- phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorImageDocumentEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorImageDocumentEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -86,6 +86,7 @@ phutil_tag( 'img', array( + 'alt' => $file->getAltText(), 'src' => $file->getBestURI(), ))); @@ -129,6 +130,7 @@ $image = phutil_tag( 'img', array( + 'alt' => $file->getAltText(), 'src' => $source_uri, )); diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorJSONDocumentEngine.php phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorJSONDocumentEngine.php --- phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorJSONDocumentEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorJSONDocumentEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -14,8 +14,12 @@ } protected function getContentScore(PhabricatorDocumentRef $ref) { - if (preg_match('/\.json\z/', $ref->getName())) { - return 2000; + + $name = $ref->getName(); + if ($name !== null) { + if (preg_match('/\.json\z/', $name)) { + return 2000; + } } if ($ref->isProbablyJSON()) { @@ -31,6 +35,17 @@ try { $data = phutil_json_decode($raw_data); + // See T13635. "phutil_json_decode()" always turns JSON into a PHP array, + // and we lose the distinction between "{}" and "[]". This distinction is + // important when rendering a document. + $data = json_decode($raw_data, false); + if (!$data) { + throw new PhabricatorDocumentEngineParserException( + pht( + 'Failed to "json_decode(...)" JSON document after successfully '. + 'decoding it with "phutil_json_decode(...).')); + } + if (preg_match('/^\s*\[/', $raw_data)) { $content = id(new PhutilJSON())->encodeAsList($data); } else { @@ -48,6 +63,13 @@ $ex->getMessage())); $content = $raw_data; + } catch (PhabricatorDocumentEngineParserException $ex) { + $message = $this->newMessage( + pht( + 'Unable to parse this document as JSON: %s', + $ex->getMessage())); + + $content = $raw_data; } return array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php --- phabricator-0~git20200925/phabricator/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/document/PhabricatorRemarkupDocumentEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,8 +15,11 @@ protected function getContentScore(PhabricatorDocumentRef $ref) { $name = $ref->getName(); - if (preg_match('/\\.remarkup\z/i', $name)) { - return 2000; + + if ($name !== null) { + if (preg_match('/\\.remarkup\z/i', $name)) { + return 2000; + } } return 500; diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/edge/PhabricatorFileHasObjectEdgeType.php phabricator-0~git20220903/phabricator/src/applications/files/edge/PhabricatorFileHasObjectEdgeType.php --- phabricator-0~git20200925/phabricator/src/applications/files/edge/PhabricatorFileHasObjectEdgeType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/edge/PhabricatorFileHasObjectEdgeType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -<?php - -final class PhabricatorFileHasObjectEdgeType extends PhabricatorEdgeType { - - const EDGECONST = 26; - - public function getInverseEdgeConstant() { - return PhabricatorObjectHasFileEdgeType::EDGECONST; - } - - public function shouldWriteInverseTransactions() { - return true; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/editor/PhabricatorFileEditEngine.php phabricator-0~git20220903/phabricator/src/applications/files/editor/PhabricatorFileEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/files/editor/PhabricatorFileEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/editor/PhabricatorFileEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -75,6 +75,14 @@ ->setConduitDescription(pht('Rename the file.')) ->setConduitTypeDescription(pht('New file name.')) ->setValue($object->getName()), + id(new PhabricatorTextEditField()) + ->setKey('alt') + ->setLabel(pht('Alt Text')) + ->setTransactionType(PhabricatorFileAltTextTransaction::TRANSACTIONTYPE) + ->setDescription(pht('Human-readable file description.')) + ->setConduitDescription(pht('Set the file alt text.')) + ->setConduitTypeDescription(pht('New alt text.')) + ->setValue($object->getCustomAltText()), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php phabricator-0~git20220903/phabricator/src/applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php --- phabricator-0~git20200925/phabricator/src/applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,6 +26,7 @@ public function canWriteFiles() { $path = PhabricatorEnv::getEnvConfig('storage.local-disk.path'); + $path = phutil_string_cast($path); return (bool)strlen($path); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php phabricator-0~git20220903/phabricator/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php --- phabricator-0~git20200925/phabricator/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,119 @@ +<?php + +final class PhabricatorFilesCurtainExtension + extends PHUICurtainExtension { + + const EXTENSIONKEY = 'files.files'; + + public function shouldEnableForObject($object) { + return true; + } + + public function getExtensionApplication() { + return new PhabricatorFilesApplication(); + } + + public function buildCurtainPanel($object) { + $viewer = $this->getViewer(); + + $attachment_table = new PhabricatorFileAttachment(); + $attachment_conn = $attachment_table->establishConnection('r'); + + $exact_limit = 100; + $visible_limit = 8; + + $attachments = id(new PhabricatorFileAttachmentQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($object->getPHID())) + ->setLimit($exact_limit + 1) + ->needFiles(true) + ->execute(); + + $visible_attachments = array_slice($attachments, 0, $visible_limit, true); + $visible_phids = mpull($visible_attachments, 'getFilePHID'); + + $handles = $viewer->loadHandles($visible_phids); + + $ref_list = id(new PHUICurtainObjectRefListView()) + ->setViewer($viewer) + ->setEmptyMessage(pht('None')); + + $view_capability = PhabricatorPolicyCapability::CAN_VIEW; + $object_policies = PhabricatorPolicyQuery::loadPolicies( + $viewer, + $object); + $object_policy = idx($object_policies, $view_capability); + + foreach ($visible_attachments as $attachment) { + $file_phid = $attachment->getFilePHID(); + $handle = $handles[$file_phid]; + + $ref = $ref_list->newObjectRefView() + ->setHandle($handle); + + $file = $attachment->getFile(); + if (!$file) { + // ... + } else { + if (!$attachment->isPolicyAttachment()) { + $file_policies = PhabricatorPolicyQuery::loadPolicies( + $viewer, + $file); + $file_policy = idx($file_policies, $view_capability); + + if ($object_policy->isStrongerThanOrEqualTo($file_policy)) { + // The file is not attached to the object, but the file policy + // allows anyone who can see the object to see the file too, so + // there is no material problem with the file not being attached. + } else { + $attach_uri = urisprintf( + '/file/ui/curtain/attach/%s/%s/', + $object->getPHID(), + $file->getPHID()); + + $attached_link = javelin_tag( + 'a', + array( + 'href' => $attach_uri, + 'sigil' => 'workflow', + ), + pht('File Not Attached')); + + $ref->setExiled( + true, + $attached_link); + } + } + } + + $epoch = $attachment->getDateCreated(); + $ref->setEpoch($epoch); + } + + $show_all = (count($visible_attachments) < count($attachments)); + if ($show_all) { + $view_all_uri = urisprintf( + '/file/ui/curtain/list/%s/', + $object->getPHID()); + + $loaded_count = count($attachments); + if ($loaded_count > $exact_limit) { + $link_text = pht('View All Files'); + } else { + $link_text = pht('View All %d Files', new PhutilNumber($loaded_count)); + } + + $ref_list->newTailLink() + ->setURI($view_all_uri) + ->setText($link_text) + ->setWorkflow(true); + } + + return $this->newPanel() + ->setHeaderText(pht('Referenced Files')) + ->setOrder(15000) + ->appendChild($ref_list); + } + + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php phabricator-0~git20220903/phabricator/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -45,6 +45,10 @@ } public function testAES256Storage() { + if (!function_exists('openssl_encrypt')) { + $this->assertSkipped(pht('No OpenSSL extension available.')); + } + $engine = new PhabricatorTestStorageEngine(); $key_name = 'test.abcd'; diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php phabricator-0~git20220903/phabricator/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php --- phabricator-0~git20200925/phabricator/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -5,7 +5,7 @@ private $viewer; - const KEY_EMBED_FILE_PHIDS = 'phabricator.embedded-file-phids'; + const KEY_ATTACH_INTENT_FILE_PHIDS = 'files.attach-intent'; protected function getObjectNamePrefix() { return 'F'; @@ -23,13 +23,44 @@ PhabricatorFileThumbnailTransform::TRANSFORM_PREVIEW, )) ->execute(); + $objects = mpull($objects, null, 'getID'); - $phids_key = self::KEY_EMBED_FILE_PHIDS; - $phids = $engine->getTextMetadata($phids_key, array()); - foreach (mpull($objects, 'getPHID') as $phid) { - $phids[] = $phid; + + // Identify files embedded in the block with "attachment intent", i.e. + // those files which the user appears to want to attach to the object. + // Files referenced inside quoted blocks are not considered to have this + // attachment intent. + + $metadata_key = self::KEY_RULE_OBJECT.'.'.$this->getObjectNamePrefix(); + $metadata = $engine->getTextMetadata($metadata_key, array()); + + $attach_key = self::KEY_ATTACH_INTENT_FILE_PHIDS; + $attach_phids = $engine->getTextMetadata($attach_key, array()); + + foreach ($metadata as $item) { + + // If this reference was inside a quoted block, don't count it. Quoting + // someone else doesn't establish an intent to attach a file. + $depth = idx($item, 'quote.depth'); + if ($depth > 0) { + continue; + } + + $id = $item['id']; + $file = idx($objects, $id); + + if (!$file) { + continue; + } + + $attach_phids[] = $file->getPHID(); } - $engine->setTextMetadata($phids_key, $phids); + + $attach_phids = array_fuse($attach_phids); + $attach_phids = array_keys($attach_phids); + + $engine->setTextMetadata($attach_key, $attach_phids); + return $objects; } @@ -161,10 +192,17 @@ } } + $alt = null; if (isset($options['alt'])) { - $attrs['alt'] = $options['alt']; + $alt = $options['alt']; + } + + if (!strlen($alt)) { + $alt = $file->getAltText(); } + $attrs['alt'] = $alt; + $img = phutil_tag('img', $attrs); $embed = javelin_tag( @@ -174,9 +212,10 @@ 'class' => $image_class, 'sigil' => 'lightboxable', 'meta' => array( - 'phid' => $file->getPHID(), - 'uri' => $file->getBestURI(), - 'dUri' => $file->getDownloadURI(), + 'phid' => $file->getPHID(), + 'uri' => $file->getBestURI(), + 'dUri' => $file->getDownloadURI(), + 'alt' => $alt, 'viewable' => true, 'monogram' => $file->getMonogram(), ), diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/phid/PhabricatorFileFilePHIDType.php phabricator-0~git20220903/phabricator/src/applications/files/phid/PhabricatorFileFilePHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/files/phid/PhabricatorFileFilePHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/phid/PhabricatorFileFilePHIDType.php 2022-06-14 16:29:55.000000000 +0000 @@ -39,6 +39,9 @@ $handle->setName("F{$id}"); $handle->setFullName("F{$id}: {$name}"); $handle->setURI($uri); + + $icon = FileTypeIcon::getFileIcon($name); + $handle->setIcon($icon); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/query/PhabricatorFileAttachmentQuery.php phabricator-0~git20220903/phabricator/src/applications/files/query/PhabricatorFileAttachmentQuery.php --- phabricator-0~git20200925/phabricator/src/applications/files/query/PhabricatorFileAttachmentQuery.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/query/PhabricatorFileAttachmentQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,131 @@ +<?php + +final class PhabricatorFileAttachmentQuery + extends PhabricatorCursorPagedPolicyAwareQuery { + + private $objectPHIDs; + private $filePHIDs; + private $needFiles; + private $visibleFiles; + + public function withObjectPHIDs(array $object_phids) { + $this->objectPHIDs = $object_phids; + return $this; + } + + public function withFilePHIDs(array $file_phids) { + $this->filePHIDs = $file_phids; + return $this; + } + + public function withVisibleFiles($visible_files) { + $this->visibleFiles = $visible_files; + return $this; + } + + public function needFiles($need) { + $this->needFiles = $need; + return $this; + } + + public function newResultObject() { + return new PhabricatorFileAttachment(); + } + + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); + + if ($this->objectPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'attachments.objectPHID IN (%Ls)', + $this->objectPHIDs); + } + + if ($this->filePHIDs !== null) { + $where[] = qsprintf( + $conn, + 'attachments.filePHID IN (%Ls)', + $this->filePHIDs); + } + + return $where; + } + + protected function willFilterPage(array $attachments) { + $viewer = $this->getViewer(); + $object_phids = array(); + + foreach ($attachments as $attachment) { + $object_phid = $attachment->getObjectPHID(); + $object_phids[$object_phid] = $object_phid; + } + + if ($object_phids) { + $objects = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->setParentQuery($this) + ->withPHIDs($object_phids) + ->execute(); + $objects = mpull($objects, null, 'getPHID'); + } else { + $objects = array(); + } + + foreach ($attachments as $key => $attachment) { + $object_phid = $attachment->getObjectPHID(); + $object = idx($objects, $object_phid); + + if (!$object) { + $this->didRejectResult($attachment); + unset($attachments[$key]); + continue; + } + + $attachment->attachObject($object); + } + + if ($this->needFiles) { + $file_phids = array(); + foreach ($attachments as $attachment) { + $file_phid = $attachment->getFilePHID(); + $file_phids[$file_phid] = $file_phid; + } + + if ($file_phids) { + $files = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->setParentQuery($this) + ->withPHIDs($file_phids) + ->execute(); + $files = mpull($files, null, 'getPHID'); + } else { + $files = array(); + } + + foreach ($attachments as $key => $attachment) { + $file_phid = $attachment->getFilePHID(); + $file = idx($files, $file_phid); + + if ($this->visibleFiles && !$file) { + $this->didRejectResult($attachment); + unset($attachments[$key]); + continue; + } + + $attachment->attachFile($file); + } + } + + return $attachments; + } + + protected function getPrimaryTableAlias() { + return 'attachments'; + } + + public function getQueryApplicationClass() { + return 'PhabricatorFilesApplication'; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/query/PhabricatorFileQuery.php phabricator-0~git20220903/phabricator/src/applications/files/query/PhabricatorFileQuery.php --- phabricator-0~git20200925/phabricator/src/applications/files/query/PhabricatorFileQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/query/PhabricatorFileQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -20,6 +20,7 @@ private $builtinKeys; private $isBuiltin; private $storageEngines; + private $attachedObjectPHIDs; public function withIDs(array $ids) { $this->ids = $ids; @@ -61,6 +62,11 @@ return $this; } + public function withAttachedObjectPHIDs(array $phids) { + $this->attachedObjectPHIDs = $phids; + return $this; + } + /** * Select files which are transformations of some other file. For example, * you can use this query to find previously generated thumbnails of an image @@ -203,16 +209,12 @@ // If we have any files left which do need objects, load the edges now. $object_phids = array(); if ($need_objects) { - $edge_type = PhabricatorFileHasObjectEdgeType::EDGECONST; - $file_phids = mpull($need_objects, 'getPHID'); - - $edges = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs($file_phids) - ->withEdgeTypes(array($edge_type)) - ->execute(); + $attachments_map = $this->newAttachmentsMap($need_objects); foreach ($need_objects as $file) { - $phids = array_keys($edges[$file->getPHID()][$edge_type]); + $file_phid = $file->getPHID(); + $phids = $attachments_map[$file_phid]; + $file->attachObjectPHIDs($phids); if ($is_omnipotent) { @@ -299,6 +301,32 @@ return $files; } + private function newAttachmentsMap(array $files) { + $file_phids = mpull($files, 'getPHID'); + + $attachments_table = new PhabricatorFileAttachment(); + $attachments_conn = $attachments_table->establishConnection('r'); + + $attachments = queryfx_all( + $attachments_conn, + 'SELECT filePHID, objectPHID FROM %R WHERE filePHID IN (%Ls) + AND attachmentMode IN (%Ls)', + $attachments_table, + $file_phids, + array( + PhabricatorFileAttachment::MODE_ATTACH, + )); + + $attachments_map = array_fill_keys($file_phids, array()); + foreach ($attachments as $row) { + $file_phid = $row['filePHID']; + $object_phid = $row['objectPHID']; + $attachments_map[$file_phid][] = $object_phid; + } + + return $attachments_map; + } + protected function didFilterPage(array $files) { $xform_keys = $this->needTransforms; if ($xform_keys !== null) { @@ -347,9 +375,24 @@ id(new PhabricatorTransformedFile())->getTableName()); } + if ($this->shouldJoinAttachmentsTable()) { + $joins[] = qsprintf( + $conn, + 'JOIN %R attachments ON attachments.filePHID = f.phid + AND attachmentMode IN (%Ls)', + new PhabricatorFileAttachment(), + array( + PhabricatorFileAttachment::MODE_ATTACH, + )); + } + return $joins; } + private function shouldJoinAttachmentsTable() { + return ($this->attachedObjectPHIDs !== null); + } + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); @@ -482,6 +525,13 @@ $this->storageEngines); } + if ($this->attachedObjectPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'attachments.objectPHID IN (%Ls)', + $this->attachedObjectPHIDs); + } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/storage/PhabricatorFileAttachment.php phabricator-0~git20220903/phabricator/src/applications/files/storage/PhabricatorFileAttachment.php --- phabricator-0~git20200925/phabricator/src/applications/files/storage/PhabricatorFileAttachment.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/storage/PhabricatorFileAttachment.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,123 @@ +<?php + +final class PhabricatorFileAttachment + extends PhabricatorFileDAO + implements + PhabricatorPolicyInterface, + PhabricatorExtendedPolicyInterface { + + protected $objectPHID; + protected $filePHID; + protected $attacherPHID; + protected $attachmentMode; + + private $object = self::ATTACHABLE; + private $file = self::ATTACHABLE; + + const MODE_ATTACH = 'attach'; + const MODE_REFERENCE = 'reference'; + const MODE_DETACH = 'detach'; + + protected function getConfiguration() { + return array( + self::CONFIG_COLUMN_SCHEMA => array( + 'objectPHID' => 'phid', + 'filePHID' => 'phid', + 'attacherPHID' => 'phid?', + 'attachmentMode' => 'text32', + ), + self::CONFIG_KEY_SCHEMA => array( + 'key_object' => array( + 'columns' => array('objectPHID', 'filePHID'), + 'unique' => true, + ), + 'key_file' => array( + 'columns' => array('filePHID'), + ), + ), + ) + parent::getConfiguration(); + } + + public static function getModeList() { + return array( + self::MODE_ATTACH, + self::MODE_REFERENCE, + self::MODE_DETACH, + ); + } + + public static function getModeNameMap() { + return array( + self::MODE_ATTACH => pht('Attached'), + self::MODE_REFERENCE => pht('Referenced'), + ); + } + + public function isPolicyAttachment() { + switch ($this->getAttachmentMode()) { + case self::MODE_ATTACH: + return true; + default: + return false; + } + } + + public function attachObject($object) { + $this->object = $object; + return $this; + } + + public function getObject() { + return $this->assertAttached($this->object); + } + + public function attachFile(PhabricatorFile $file = null) { + $this->file = $file; + return $this; + } + + public function getFile() { + return $this->assertAttached($this->file); + } + + public function canDetach() { + switch ($this->getAttachmentMode()) { + case self::MODE_ATTACH: + return true; + } + + return false; + } + + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + + public function getPolicy($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return PhabricatorPolicies::getMostOpenPolicy(); + } + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return false; + } + + +/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */ + + + public function getExtendedPolicy($capability, PhabricatorUser $viewer) { + return array( + array($this->getObject(), $capability), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/storage/PhabricatorFile.php phabricator-0~git20220903/phabricator/src/applications/files/storage/PhabricatorFile.php --- phabricator-0~git20200925/phabricator/src/applications/files/storage/PhabricatorFile.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/storage/PhabricatorFile.php 2022-06-14 16:29:55.000000000 +0000 @@ -41,6 +41,7 @@ const METADATA_STORAGE = 'storage'; const METADATA_INTEGRITY = 'integrity'; const METADATA_CHUNK = 'chunk'; + const METADATA_ALT_TEXT = 'alt'; const STATUS_ACTIVE = 'active'; const STATUS_DELETED = 'deleted'; @@ -1274,6 +1275,72 @@ return idx($this->metadata, self::METADATA_IMAGE_WIDTH); } + public function getAltText() { + $alt = $this->getCustomAltText(); + + if (strlen($alt)) { + return $alt; + } + + return $this->getDefaultAltText(); + } + + public function getCustomAltText() { + return idx($this->metadata, self::METADATA_ALT_TEXT); + } + + public function setCustomAltText($value) { + $value = phutil_string_cast($value); + + if (!strlen($value)) { + $value = null; + } + + if ($value === null) { + unset($this->metadata[self::METADATA_ALT_TEXT]); + } else { + $this->metadata[self::METADATA_ALT_TEXT] = $value; + } + + return $this; + } + + public function getDefaultAltText() { + $parts = array(); + + $name = $this->getName(); + if (strlen($name)) { + $parts[] = $name; + } + + $stats = array(); + + $image_x = $this->getImageHeight(); + $image_y = $this->getImageWidth(); + + if ($image_x && $image_y) { + $stats[] = pht( + "%d\xC3\x97%d px", + new PhutilNumber($image_x), + new PhutilNumber($image_y)); + } + + $bytes = $this->getByteSize(); + if ($bytes) { + $stats[] = phutil_format_bytes($bytes); + } + + if ($stats) { + $parts[] = pht('(%s)', implode(', ', $stats)); + } + + if (!$parts) { + return null; + } + + return implode(' ', $parts); + } + public function getCanCDN() { if (!$this->isViewableImage()) { return false; @@ -1349,28 +1416,25 @@ * @return this */ public function attachToObject($phid) { - $edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST; + $attachment_table = new PhabricatorFileAttachment(); + $attachment_conn = $attachment_table->establishConnection('w'); - id(new PhabricatorEdgeEditor()) - ->addEdge($phid, $edge_type, $this->getPHID()) - ->save(); - - return $this; - } - - - /** - * Remove the policy edge between this file and some object. - * - * @param phid Object PHID to detach from. - * @return this - */ - public function detachFromObject($phid) { - $edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST; - - id(new PhabricatorEdgeEditor()) - ->removeEdge($phid, $edge_type, $this->getPHID()) - ->save(); + queryfx( + $attachment_conn, + 'INSERT INTO %R (objectPHID, filePHID, attachmentMode, + attacherPHID, dateCreated, dateModified) + VALUES (%s, %s, %s, %ns, %d, %d) + ON DUPLICATE KEY UPDATE + attachmentMode = VALUES(attachmentMode), + attacherPHID = VALUES(attacherPHID), + dateModified = VALUES(dateModified)', + $attachment_table, + $phid, + $this->getPHID(), + PhabricatorFileAttachment::MODE_ATTACH, + null, + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); return $this; } @@ -1676,6 +1740,10 @@ 'uri' => PhabricatorEnv::getURI($this->getURI()), 'dataURI' => $this->getCDNURI('data'), 'size' => (int)$this->getByteSize(), + 'alt' => array( + 'custom' => $this->getCustomAltText(), + 'default' => $this->getDefaultAltText(), + ), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php phabricator-0~git20220903/phabricator/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/storage/__tests__/PhabricatorFileTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -100,7 +100,14 @@ $xactions[] = id(new ManiphestTransaction()) ->setTransactionType( ManiphestTaskDescriptionTransaction::TRANSACTIONTYPE) - ->setNewValue('{'.$file->getMonogram().'}'); + ->setNewValue('{'.$file->getMonogram().'}') + ->setMetadataValue( + 'remarkup.control', + array( + 'attachedFilePHIDs' => array( + $file->getPHID(), + ), + )); id(new ManiphestTransactionEditor()) ->setActor($author) @@ -167,9 +174,10 @@ // Create an object and test object policies. - $object = ManiphestTask::initializeNewTask($author); - $object->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()); - $object->save(); + $object = ManiphestTask::initializeNewTask($author) + ->setTitle(pht('File Visibility Test Task')) + ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) + ->save(); $this->assertTrue( $filter->hasCapability( @@ -185,10 +193,53 @@ PhabricatorPolicyCapability::CAN_VIEW), pht('Object Visible to Others')); + // Reference the file in a comment. This should not affect the file + // policy. + + $file_ref = '{F'.$file->getID().'}'; + + $xactions = array(); + $xactions[] = id(new ManiphestTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) + ->attachComment( + id(new ManiphestTransactionComment()) + ->setContent($file_ref)); + + id(new ManiphestTransactionEditor()) + ->setActor($author) + ->setContentSource($this->newContentSource()) + ->applyTransactions($object, $xactions); + + // Test the referenced file's visibility. + $this->assertEqual( + array( + true, + false, + ), + $this->canViewFile($users, $file), + pht('Referenced File Visibility')); + // Attach the file to the object and test that the association opens a // policy exception for the non-author viewer. - $file->attachToObject($object->getPHID()); + $xactions = array(); + $xactions[] = id(new ManiphestTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) + ->setMetadataValue( + 'remarkup.control', + array( + 'attachedFilePHIDs' => array( + $file->getPHID(), + ), + )) + ->attachComment( + id(new ManiphestTransactionComment()) + ->setContent($file_ref)); + + id(new ManiphestTransactionEditor()) + ->setActor($author) + ->setContentSource($this->newContentSource()) + ->applyTransactions($object, $xactions); // Test the attached file's visibility. $this->assertEqual( @@ -224,18 +275,6 @@ ), $this->canViewFile($users, $xform), pht('Attached Thumbnail Visibility')); - - // Detach the object and make sure it affects the thumbnail. - $file->detachFromObject($object->getPHID()); - - // Test the detached thumbnail's visibility. - $this->assertEqual( - array( - true, - false, - ), - $this->canViewFile($users, $xform), - pht('Detached Thumbnail Visibility')); } private function canViewFile(array $users, PhabricatorFile $file) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php phabricator-0~git20220903/phabricator/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/files/xaction/PhabricatorFileAltTextTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,94 @@ +<?php + +final class PhabricatorFileAltTextTransaction + extends PhabricatorFileTransactionType { + + const TRANSACTIONTYPE = 'file:alt'; + + public function generateOldValue($object) { + return $object->getCustomAltText(); + } + + public function generateNewValue($object, $value) { + $value = phutil_string_cast($value); + + if (!strlen($value)) { + $value = null; + } + + return $value; + } + + public function applyInternalEffects($object, $value) { + $object->setCustomAltText($value); + } + + public function getTitle() { + $old_value = $this->getOldValue(); + $new_value = $this->getNewValue(); + + if (!strlen($old_value)) { + return pht( + '%s set the alternate text for this file to %s.', + $this->renderAuthor(), + $this->renderNewValue()); + } else if (!strlen($new_value)) { + return pht( + '%s removed the alternate text for this file (was %s).', + $this->renderAuthor(), + $this->renderOldValue()); + } else { + return pht( + '%s changed the alternate text for this file from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old_value = $this->getOldValue(); + $new_value = $this->getNewValue(); + + if (!strlen($old_value)) { + return pht( + '%s set the alternate text for %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewValue()); + } else if (!strlen($new_value)) { + return pht( + '%s removed the alternate text for %s (was %s).', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue()); + } else { + return pht( + '%s changed the alternate text for %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $max_length = 1024; + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht( + 'File alternate text must not be longer than %s character(s).', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/fund/query/FundInitiativeQuery.php phabricator-0~git20220903/phabricator/src/applications/fund/query/FundInitiativeQuery.php --- phabricator-0~git20200925/phabricator/src/applications/fund/query/FundInitiativeQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/fund/query/FundInitiativeQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new FundInitiative(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/fund/storage/FundInitiative.php phabricator-0~git20220903/phabricator/src/applications/fund/storage/FundInitiative.php --- phabricator-0~git20200925/phabricator/src/applications/fund/storage/FundInitiative.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/fund/storage/FundInitiative.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,7 +22,6 @@ protected $editPolicy; protected $status; protected $totalAsCurrency; - protected $mailKey; private $projectPHIDs = self::ATTACHABLE; @@ -62,7 +61,6 @@ 'status' => 'text32', 'merchantPHID' => 'phid?', 'totalAsCurrency' => 'text64', - 'mailKey' => 'bytes20', ), self::CONFIG_APPLICATION_SERIALIZERS => array( 'totalAsCurrency' => new PhortuneCurrencySerializer(), @@ -78,8 +76,8 @@ ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID(FundInitiativePHIDType::TYPECONST); + public function getPHIDType() { + return FundInitiativePHIDType::TYPECONST; } public function getMonogram() { @@ -103,13 +101,6 @@ return ($this->getStatus() == self::STATUS_CLOSED); } - public function save() { - if (!$this->mailKey) { - $this->mailKey = Filesystem::readRandomCharacters(20); - } - return parent::save(); - } - /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/guides/module/PhabricatorGuideInstallModule.php phabricator-0~git20220903/phabricator/src/applications/guides/module/PhabricatorGuideInstallModule.php --- phabricator-0~git20200925/phabricator/src/applications/guides/module/PhabricatorGuideInstallModule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/guides/module/PhabricatorGuideInstallModule.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,7 +7,7 @@ } public function getModuleName() { - return pht('Install Phabricator'); + return pht('Install'); } public function getModulePosition() { @@ -66,7 +66,7 @@ $icon_bg = 'bg-sky'; $description = pht( 'Authentication providers allow users to register accounts and '. - 'log in to Phabricator.'); + 'log in.'); } $item = id(new PhabricatorGuideItemView()) @@ -78,7 +78,7 @@ $guide_items->addItem($item); - $title = pht('Configure Phabricator'); + $title = pht('Configure'); $href = PhabricatorEnv::getURI('/config/'); // Just load any config value at all; if one exists the install has figured @@ -95,7 +95,7 @@ $icon = 'fa-sliders'; $icon_bg = 'bg-sky'; $description = pht( - 'Learn how to configure mail and other options in Phabricator.'); + 'Learn how to configure mail and other options.'); } $item = id(new PhabricatorGuideItemView()) @@ -148,7 +148,7 @@ $icon = 'fa-bell'; $icon_bg = 'bg-sky'; $description = pht( - 'Phabricator can deliver notifications in real-time with WebSockets.'); + 'Real-time notifications can be delivered with WebSockets.'); } $item = id(new PhabricatorGuideItemView()) @@ -161,11 +161,12 @@ $guide_items->addItem($item); $intro = pht( - 'Phabricator has been successfully installed. These next guides will '. + '%s has been successfully installed. These next guides will '. 'take you through configuration and new user orientation. '. 'These steps are optional, and you can go through them in any order. '. 'If you want to get back to this guide later on, you can find it in '. - '{icon globe} **Applications** under {icon map-o} **Guides**.'); + '{icon globe} **Applications** under {icon map-o} **Guides**.', + PlatformSymbols::getPlatformServerName()); $intro = new PHUIRemarkupView($viewer, $intro); diff -Nru phabricator-0~git20200925/phabricator/src/applications/guides/module/PhabricatorGuideQuickStartModule.php phabricator-0~git20220903/phabricator/src/applications/guides/module/PhabricatorGuideQuickStartModule.php --- phabricator-0~git20200925/phabricator/src/applications/guides/module/PhabricatorGuideQuickStartModule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/guides/module/PhabricatorGuideQuickStartModule.php 2022-06-14 16:29:55.000000000 +0000 @@ -132,7 +132,7 @@ $icon = 'fa-globe'; $icon_bg = 'bg-sky'; $description = - pht('See all the applications included in Phabricator.'); + pht('See all available applications.'); $item = id(new PhabricatorGuideItemView()) ->setTitle($title) @@ -159,7 +159,7 @@ $icon = 'fa-group'; $icon_bg = 'bg-sky'; $description = - pht('Invite the rest of your team to get started on Phabricator.'); + pht('Invite the rest of your team to get started.'); } $item = id(new PhabricatorGuideItemView()) @@ -172,11 +172,9 @@ } $intro = pht( - 'If you\'re new to Phabricator, these optional steps can help you learn '. - 'the basics. Conceptually, Phabricator is structured as a graph, and '. - 'repositories, tasks, and projects are all independent from each other. '. - 'Feel free to set up Phabricator for how you work best, and explore '. - 'these features at your own pace.'); + 'If you\'re new to this software, these optional steps can help you '. + 'learn the basics. Feel free to set things up for how you work best '. + 'and explore these features at your own pace.'); $intro = new PHUIRemarkupView($viewer, $intro); $intro = id(new PHUIDocumentView()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/artifact/HarbormasterFileArtifact.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/artifact/HarbormasterFileArtifact.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/artifact/HarbormasterFileArtifact.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/artifact/HarbormasterFileArtifact.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,8 +10,7 @@ public function getArtifactTypeDescription() { return pht( - 'Stores a reference to file data which has been uploaded to '. - 'Phabricator.'); + 'Stores a reference to file data.'); } public function getArtifactParameterSpecification() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildableEditAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildableEditAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildableEditAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildableEditAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,20 @@ +<?php + +final class HarbormasterBuildableEditAPIMethod + extends PhabricatorEditEngineAPIMethod { + + public function getAPIMethodName() { + return 'harbormaster.buildable.edit'; + } + + public function newEditEngine() { + return new HarbormasterBuildableEditEngine(); + } + + public function getMethodSummary() { + return pht( + 'Apply transactions to create a new buildable or edit an existing '. + 'one.'); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildEditAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildEditAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildEditAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildEditAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,20 @@ +<?php + +final class HarbormasterBuildEditAPIMethod + extends PhabricatorEditEngineAPIMethod { + + public function getAPIMethodName() { + return 'harbormaster.build.edit'; + } + + public function newEditEngine() { + return new HarbormasterBuildEditEngine(); + } + + public function getMethodSummary() { + return pht( + 'Apply transactions to create a new build or edit an existing '. + 'one.'); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepEditAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepEditAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepEditAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepEditAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,20 @@ +<?php + +final class HarbormasterBuildStepEditAPIMethod + extends PhabricatorEditEngineAPIMethod { + + public function getAPIMethodName() { + return 'harbormaster.step.edit'; + } + + public function newEditEngine() { + return new HarbormasterBuildStepEditEngine(); + } + + public function getMethodSummary() { + return pht( + 'Apply transactions to create a new build step or edit an existing '. + 'one.'); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepSearchAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepSearchAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepSearchAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterBuildStepSearchAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,18 @@ +<?php + +final class HarbormasterBuildStepSearchAPIMethod + extends PhabricatorSearchEngineAPIMethod { + + public function getAPIMethodName() { + return 'harbormaster.step.search'; + } + + public function newSearchEngine() { + return new HarbormasterBuildStepSearchEngine(); + } + + public function getMethodSummary() { + return pht('Retrieve information about Harbormaster build steps.'); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,14 +7,6 @@ 'PhabricatorHarbormasterApplication'); } - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodStatusDescription() { - return pht('All Harbormaster APIs are new and subject to change.'); - } - protected function returnArtifactList(array $artifacts) { $list = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/conduit/HarbormasterSendMessageConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,18 +9,222 @@ public function getMethodSummary() { return pht( - 'Send a message about the status of a build target to Harbormaster, '. - 'notifying the application of build results in an external system.'); + 'Modify running builds, and report build results.'); } public function getMethodDescription() { + return pht(<<<EOREMARKUP +Pause, abort, restart, and report results for builds. +EOREMARKUP + ); + } + + protected function newDocumentationPages(PhabricatorUser $viewer) { + $pages = array(); + + $pages[] = $this->newSendingDocumentationBoxPage($viewer); + $pages[] = $this->newBuildsDocumentationBoxPage($viewer); + $pages[] = $this->newCommandsDocumentationBoxPage($viewer); + $pages[] = $this->newTargetsDocumentationBoxPage($viewer); + $pages[] = $this->newUnitDocumentationBoxPage($viewer); + $pages[] = $this->newLintDocumentationBoxPage($viewer); + + return $pages; + } + + private function newSendingDocumentationBoxPage(PhabricatorUser $viewer) { + $title = pht('Sending Messages'); + $content = pht(<<<EOREMARKUP +Harbormaster build objects work somewhat differently from objects in many other +applications. Most application objects can be edited directly using synchronous +APIs (like `maniphest.edit`, `differential.revision.edit`, and so on). + +However, builds require long-running background processing and Habormaster +objects have a more complex lifecycle than most other application objects and +may spend significant periods of time locked by daemon processes during build +execition. A synchronous edit might need to wait an arbitrarily long amount of +time for this lock to become available so the edit could be applied. + +Additionally, some edits may also require an arbitrarily long amount of time to +//complete//. For example, aborting a build may execute cleanup steps which +take minutes (or even hours) to complete. + +Since a synchronous API could not guarantee it could return results to the +caller in a reasonable amount of time, the edit API for Harbormaster build +objects is asynchronous: to update a Harbormaster build or build target, use +this API (`harbormaster.sendmessage`) to send it a message describing an edit +you would like to effect or additional information you want to provide. +The message will be processed by the daemons once the build or target reaches +a suitable state to receive messages. + +Select an object to send a message to using the `receiver` parameter. This +API method can send messages to multiple types of objects: + +<table> + <tr> + <th>Object Type</th> + <th>PHID Example</th> + <th>Description</th> + </tr> + <tr> + <td>Harbormaster Buildable</td> + <td>`PHID-HMBB-...`</td> + <td>%s</td> + </tr> + <tr> + <td>Harbormaster Build</td> + <td>`PHID-HMBD-...`</td> + <td>%s</td> + </tr> + <tr> + <td>Harbormaster Build Target</td> + <td>`PHID-HMBT-...`</td> + <td>%s</td> + </tr> +</table> + +See below for specifics on sending messages to different object types. +EOREMARKUP + , + pht( + 'Buildables may receive control commands like "abort" and "restart". '. + 'Sending a control command to a Buildable is the same as sending it '. + 'to each Build for the Buildable.'), + pht( + 'Builds may receive control commands like "pause", "resume", "abort", '. + 'and "restart".'), + pht( + 'Build Targets may receive build status and result messages, like '. + '"pass" or "fail".')); + + $content = $this->newRemarkupDocumentationView($content); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('sending') + ->setIconIcon('fa-envelope-o'); + } + + private function newBuildsDocumentationBoxPage(PhabricatorUser $viewer) { + $title = pht('Updating Builds'); + + $content = pht(<<<EOREMARKUP +You can use this method (`harbormaster.sendmessage`) to send control commands +to Buildables and Builds. + +Specify the Build or Buildable to receive the control command by providing its +PHID in the `receiver` parameter. + +Sending a control command to a Buildable has the same effect as sending it to +each Build for the Buildable. For example, sending a "Pause" message to a +Buildable will pause all builds for the Buildable (or at least attempt to). + +When sending control commands, the `unit` and `lint` parameters of this API +method must be omitted. You can not report lint or unit results directly to +a Build or Buildable, and can not report them alongside a control command. + +More broadly, you can not report build results directly to a Build or +Buildable. Instead, report results to a Build Target. + +See below for a list of control commands. + +EOREMARKUP + ); + + $content = $this->newRemarkupDocumentationView($content); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('builds') + ->setIconIcon('fa-cubes'); + } + + private function newCommandsDocumentationBoxPage(PhabricatorUser $viewer) { + $messages = HarbormasterBuildMessageTransaction::getAllMessages(); + + $rows = array(); + + $rows[] = '<tr>'; + $rows[] = '<th>'.pht('Message Type').'</th>'; + $rows[] = '<th>'.pht('Description').'</th>'; + $rows[] = '</tr>'; + + foreach ($messages as $message) { + $row = array(); + + $row[] = sprintf( + '<td>`%s`</td>', + $message->getHarbormasterBuildMessageType()); + + $row[] = sprintf( + '<td>%s</td>', + $message->getHarbormasterBuildMessageDescription()); + + $rows[] = sprintf( + '<tr>%s</tr>', + implode("\n", $row)); + } + + $message_table = sprintf( + '<table>%s</table>', + implode("\n", $rows)); + + $title = pht('Control Commands'); + + $content = pht(<<<EOREMARKUP +You can use this method to send control commands to Buildables and Builds. + +This table summarizes which object types may receive control commands: + +<table> + <tr> + <th>Object Type</th> + <th>PHID Example</th> + <th /> + <th>Description</th> + </tr> + <tr> + <td>Harbormaster Buildable</td> + <td>`PHID-HMBB-...`</td> + <td>{icon check color=green}</td> + <td>Buildables may receive control commands.</td> + </tr> + <tr> + <td>Harbormaster Build</td> + <td>`PHID-HMBD-...`</td> + <td>{icon check color=green}</td> + <td>Builds may receive control commands.</td> + </tr> + <tr> + <td>Harbormaster Build Target</td> + <td>`PHID-HMBT-...`</td> + <td>{icon times color=red}</td> + <td>You may **NOT** send control commands to build targets.</td> + </tr> +</table> + +You can send these commands: + +%s + +To send a command message, specify the PHID of the object you would like to +receive the message using the `receiver` parameter, and specify the message +type using the `type` parameter. + +EOREMARKUP + , + $message_table); + + $content = $this->newRemarkupDocumentationView($content); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('commands') + ->setIconIcon('fa-exclamation-triangle'); + } + + private function newTargetsDocumentationBoxPage(PhabricatorUser $viewer) { $messages = HarbormasterMessageType::getAllMessages(); - $head_type = pht('Constant'); - $head_desc = pht('Description'); - $head_key = pht('Key'); $head_type = pht('Type'); - $head_name = pht('Name'); + $head_desc = pht('Description'); $rows = array(); $rows[] = "| {$head_type} | {$head_desc} |"; @@ -31,6 +235,84 @@ } $message_table = implode("\n", $rows); + $content = pht(<<<EOREMARKUP +If you run external builds, you can use this method to publish build results +back into Harbormaster after the external system finishes work (or as it makes +progress). + +To report build status or results, you must send a message to the appropriate +Build Target. This table summarizes which object types may receive build status +and result messages: + +<table> + <tr> + <th>Object Type</th> + <th>PHID Example</th> + <th /> + <th>Description</th> + </tr> + <tr> + <td>Harbormaster Buildable</td> + <td>`PHID-HMBB-...`</td> + <td>{icon times color=red}</td> + <td>Buildables may **NOT** receive status or result messages.</td> + </tr> + <tr> + <td>Harbormaster Build</td> + <td>`PHID-HMBD-...`</td> + <td>{icon times color=red}</td> + <td>Builds may **NOT** receive status or result messages.</td> + </tr> + <tr> + <td>Harbormaster Build Target</td> + <td>`PHID-HMBT-...`</td> + <td>{icon check color=green}</td> + <td>Report build status and results to Build Targets.</td> + </tr> +</table> + +The simplest way to use this method to report build results is to call it once +after the build finishes with a `pass` or `fail` message. This will record the +build result, and continue the next step in the build if the build was waiting +for a result. + +When you send a status message about a build target, you can optionally include +detailed `lint` or `unit` results alongside the message. See below for details. + +If you want to report intermediate results but a build hasn't completed yet, +you can use the `work` message. This message doesn't have any direct effects, +but allows you to send additional data to update the progress of the build +target. The target will continue waiting for a completion message, but the UI +will update to show the progress which has been made. + +When sending a message to a build target to report the status or results of +a build, your message must include a `type` which describes the overall state +of the build. For example, use `pass` to tell Harbormaster that a build target +completed successfully. + +Supported message types are: + +%s + +EOREMARKUP + , + $message_table); + + $title = pht('Updating Build Targets'); + + $content = $this->newRemarkupDocumentationView($content); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('targets') + ->setIconIcon('fa-bullseye'); + } + + private function newUnitDocumentationBoxPage(PhabricatorUser $viewer) { + $head_key = pht('Key'); + $head_desc = pht('Description'); + $head_name = pht('Name'); + $head_type = pht('Type'); + $rows = array(); $rows[] = "| {$head_key} | {$head_type} | {$head_desc} |"; $rows[] = '|-------------|--------------|--------------|'; @@ -55,6 +337,64 @@ } $result_table = implode("\n", $rows); + $valid_unit = array( + array( + 'name' => 'PassingTest', + 'result' => ArcanistUnitTestResult::RESULT_PASS, + ), + array( + 'name' => 'FailingTest', + 'result' => ArcanistUnitTestResult::RESULT_FAIL, + ), + ); + + $json = new PhutilJSON(); + $valid_unit = $json->encodeAsList($valid_unit); + + + $title = pht('Reporting Unit Results'); + + $content = pht(<<<EOREMARKUP +You can report test results when updating the state of a build target. The +simplest way to do this is to report all the results alongside a `pass` or +`fail` message, but you can also send a `work` message to report intermediate +results. + + +To provide unit test results, pass a list of results in the `unit` +parameter. Each result should be a dictionary with these keys: + +%s + +The `result` parameter recognizes these test results: + +%s + +This is a simple, valid value for the `unit` parameter. It reports one passing +test and one failing test: + +```lang=json +%s +``` +EOREMARKUP + , + $unit_table, + $result_table, + $valid_unit); + + $content = $this->newRemarkupDocumentationView($content); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('unit'); + } + + private function newLintDocumentationBoxPage(PhabricatorUser $viewer) { + + $head_key = pht('Key'); + $head_desc = pht('Description'); + $head_name = pht('Name'); + $head_type = pht('Type'); + $rows = array(); $rows[] = "| {$head_key} | {$head_type} | {$head_desc} |"; $rows[] = '|-------------|--------------|--------------|'; @@ -76,17 +416,6 @@ } $severity_table = implode("\n", $rows); - $valid_unit = array( - array( - 'name' => 'PassingTest', - 'result' => ArcanistUnitTestResult::RESULT_PASS, - ), - array( - 'name' => 'FailingTest', - 'result' => ArcanistUnitTestResult::RESULT_FAIL, - ), - ); - $valid_lint = array( array( 'name' => pht('Syntax Error'), @@ -109,104 +438,58 @@ ); $json = new PhutilJSON(); - $valid_unit = $json->encodeAsList($valid_unit); $valid_lint = $json->encodeAsList($valid_lint); - return pht( - "Send a message about the status of a build target to Harbormaster, ". - "notifying the application of build results in an external system.". - "\n\n". - "Sending Messages\n". - "================\n". - "If you run external builds, you can use this method to publish build ". - "results back into Harbormaster after the external system finishes work ". - "or as it makes progress.". - "\n\n". - "The simplest way to use this method is to call it once after the ". - "build finishes with a `pass` or `fail` message. This will record the ". - "build result, and continue the next step in the build if the build was ". - "waiting for a result.". - "\n\n". - "When you send a status message about a build target, you can ". - "optionally include detailed `lint` or `unit` results alongside the ". - "message. See below for details.". - "\n\n". - "If you want to report intermediate results but a build hasn't ". - "completed yet, you can use the `work` message. This message doesn't ". - "have any direct effects, but allows you to send additional data to ". - "update the progress of the build target. The target will continue ". - "waiting for a completion message, but the UI will update to show the ". - "progress which has been made.". - "\n\n". - "Message Types\n". - "=============\n". - "When you send Harbormaster a message, you must include a `type`, ". - "which describes the overall state of the build. For example, use ". - "`pass` to tell Harbormaster that a build completed successfully.". - "\n\n". - "Supported message types are:". - "\n\n". - "%s". - "\n\n". - "Unit Results\n". - "============\n". - "You can report test results alongside a message. The simplest way to ". - "do this is to report all the results alongside a `pass` or `fail` ". - "message, but you can also send a `work` message to report intermediate ". - "results.\n\n". - "To provide unit test results, pass a list of results in the `unit` ". - "parameter. Each result should be a dictionary with these keys:". - "\n\n". - "%s". - "\n\n". - "The `result` parameter recognizes these test results:". - "\n\n". - "%s". - "\n\n". - "This is a simple, valid value for the `unit` parameter. It reports ". - "one passing test and one failing test:\n\n". - "\n\n". - "```lang=json\n". - "%s". - "```". - "\n\n". - "Lint Results\n". - "============\n". - "Like unit test results, you can report lint results alongside a ". - "message. The `lint` parameter should contain results as a list of ". - "dictionaries with these keys:". - "\n\n". - "%s". - "\n\n". - "The `severity` parameter recognizes these severity levels:". - "\n\n". - "%s". - "\n\n". - "This is a simple, valid value for the `lint` parameter. It reports one ". - "error and one warning:". - "\n\n". - "```lang=json\n". - "%s". - "```". - "\n\n", - $message_table, - $unit_table, - $result_table, - $valid_unit, + $title = pht('Reporting Lint Results'); + $content = pht(<<<EOREMARKUP +Like unit test results, you can report lint results when updating the state +of a build target. The `lint` parameter should contain results as a list of +dictionaries with these keys: + +%s + +The `severity` parameter recognizes these severity levels: + +%s + +This is a simple, valid value for the `lint` parameter. It reports one error +and one warning: + +```lang=json +%s +``` + +EOREMARKUP + , $lint_table, $severity_table, $valid_lint); + + $content = $this->newRemarkupDocumentationView($content); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('lint'); } protected function defineParamTypes() { $messages = HarbormasterMessageType::getAllMessages(); + + $more_messages = HarbormasterBuildMessageTransaction::getAllMessages(); + $more_messages = mpull($more_messages, 'getHarbormasterBuildMessageType'); + + $messages = array_merge($messages, $more_messages); + $messages = array_unique($messages); + + sort($messages); + $type_const = $this->formatStringConstants($messages); return array( - 'buildTargetPHID' => 'required phid', + 'receiver' => 'required string|phid', 'type' => 'required '.$type_const, 'unit' => 'optional list<wild>', 'lint' => 'optional list<wild>', + 'buildTargetPHID' => 'deprecated optional phid', ); } @@ -215,19 +498,90 @@ } protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); + $viewer = $request->getViewer(); + + $receiver_name = $request->getValue('receiver'); $build_target_phid = $request->getValue('buildTargetPHID'); + if ($build_target_phid !== null) { + if ($receiver_name === null) { + $receiver_name = $build_target_phid; + } else { + throw new Exception( + pht( + 'Call specifies both "receiver" and "buildTargetPHID". '. + 'When using the modern "receiver" parameter, omit the '. + 'deprecated "buildTargetPHID" parameter.')); + } + } + + if (!strlen($receiver_name)) { + throw new Exception( + pht( + 'Call omits required "receiver" parameter. Specify the PHID '. + 'of the object you want to send a message to.')); + } + $message_type = $request->getValue('type'); + if (!strlen($message_type)) { + throw new Exception( + pht( + 'Call omits required "type" parameter. Specify the type of '. + 'message you want to send.')); + } - $build_target = id(new HarbormasterBuildTargetQuery()) + $receiver_object = id(new PhabricatorObjectQuery()) ->setViewer($viewer) - ->withPHIDs(array($build_target_phid)) + ->withNames(array($receiver_name)) ->executeOne(); - if (!$build_target) { - throw new Exception(pht('No such build target!')); + if (!$receiver_object) { + throw new Exception( + pht( + 'Unable to load object "%s" to receive message.', + $receiver_name)); + } + + $is_target = ($receiver_object instanceof HarbormasterBuildTarget); + if ($is_target) { + return $this->sendToTarget($request, $message_type, $receiver_object); + } + + if ($request->getValue('unit') !== null) { + throw new Exception( + pht( + 'Call includes "unit" parameter. This parameter must be omitted '. + 'when the receiver is not a Build Target.')); } + if ($request->getValue('lint') !== null) { + throw new Exception( + pht( + 'Call includes "lint" parameter. This parameter must be omitted '. + 'when the receiver is not a Build Target.')); + } + + $is_build = ($receiver_object instanceof HarbormasterBuild); + if ($is_build) { + return $this->sendToBuild($request, $message_type, $receiver_object); + } + + $is_buildable = ($receiver_object instanceof HarbormasterBuildable); + if ($is_buildable) { + return $this->sendToBuildable($request, $message_type, $receiver_object); + } + + throw new Exception( + pht( + 'Receiver object (of class "%s") is not a valid receiver.', + get_class($receiver_object))); + } + + private function sendToTarget( + ConduitAPIRequest $request, + $message_type, + HarbormasterBuildTarget $build_target) { + $viewer = $request->getViewer(); + $save = array(); $lint_messages = $request->getValue('lint', array()); @@ -270,4 +624,67 @@ return null; } + private function sendToBuild( + ConduitAPIRequest $request, + $message_type, + HarbormasterBuild $build) { + $viewer = $request->getViewer(); + + $xaction = + HarbormasterBuildMessageTransaction::getTransactionObjectForMessageType( + $message_type); + if (!$xaction) { + throw new Exception( + pht( + 'Message type "%s" is not supported.', + $message_type)); + } + + // NOTE: This is a slightly weaker check than we perform in the web UI. + // We allow API callers to send a "pause" message to a pausing build, + // for example, even though the message will have no effect. + $xaction->assertCanApplyMessage($viewer, $build); + + $build->sendMessage($viewer, $xaction->getHarbormasterBuildMessageType()); + } + + private function sendToBuildable( + ConduitAPIRequest $request, + $message_type, + HarbormasterBuildable $buildable) { + $viewer = $request->getViewer(); + + $xaction = + HarbormasterBuildMessageTransaction::getTransactionObjectForMessageType( + $message_type); + if (!$xaction) { + throw new Exception( + pht( + 'Message type "%s" is not supported.', + $message_type)); + } + + // Reload the Buildable to load Builds. + $buildable = id(new HarbormasterBuildableQuery()) + ->setViewer($viewer) + ->withIDs(array($buildable->getID())) + ->needBuilds(true) + ->executeOne(); + + $can_send = array(); + foreach ($buildable->getBuilds() as $build) { + if ($xaction->canApplyMessage($viewer, $build)) { + $can_send[] = $build; + } + } + + // NOTE: This doesn't actually apply a transaction to the Buildable, + // but that transaction is purely informational and should probably be + // implemented as a Message. + + foreach ($can_send as $build) { + $build->sendMessage($viewer, $xaction->getHarbormasterBuildMessageType()); + } + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/constants/HarbormasterBuildStatus.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/constants/HarbormasterBuildStatus.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/constants/HarbormasterBuildStatus.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/constants/HarbormasterBuildStatus.php 2022-06-14 16:29:55.000000000 +0000 @@ -12,6 +12,11 @@ const STATUS_PAUSED = 'paused'; const STATUS_DEADLOCKED = 'deadlocked'; + const PENDING_PAUSING = 'x-pausing'; + const PENDING_RESUMING = 'x-resuming'; + const PENDING_RESTARTING = 'x-restarting'; + const PENDING_ABORTING = 'x-aborting'; + private $key; private $properties; @@ -56,6 +61,37 @@ return ($this->key === self::STATUS_FAILED); } + public function isAborting() { + return ($this->key === self::PENDING_ABORTING); + } + + public function isRestarting() { + return ($this->key === self::PENDING_RESTARTING); + } + + public function isResuming() { + return ($this->key === self::PENDING_RESUMING); + } + + public function isPausing() { + return ($this->key === self::PENDING_PAUSING); + } + + public function isPending() { + return ($this->key === self::STATUS_PENDING); + } + + public function getIconIcon() { + return $this->getProperty('icon'); + } + + public function getIconColor() { + return $this->getProperty('color'); + } + + public function getName() { + return $this->getProperty('name'); + } /** * Get a human readable name for a build status constant. @@ -185,8 +221,8 @@ ), self::STATUS_PAUSED => array( 'name' => pht('Paused'), - 'icon' => 'fa-minus-circle', - 'color' => 'dark', + 'icon' => 'fa-pause', + 'color' => 'yellow', 'color.ansi' => 'yellow', 'isBuilding' => false, 'isComplete' => false, @@ -199,6 +235,38 @@ 'isBuilding' => false, 'isComplete' => true, ), + self::PENDING_PAUSING => array( + 'name' => pht('Pausing'), + 'icon' => 'fa-exclamation-triangle', + 'color' => 'red', + 'color.ansi' => 'red', + 'isBuilding' => false, + 'isComplete' => false, + ), + self::PENDING_RESUMING => array( + 'name' => pht('Resuming'), + 'icon' => 'fa-exclamation-triangle', + 'color' => 'red', + 'color.ansi' => 'red', + 'isBuilding' => false, + 'isComplete' => false, + ), + self::PENDING_RESTARTING => array( + 'name' => pht('Restarting'), + 'icon' => 'fa-exclamation-triangle', + 'color' => 'red', + 'color.ansi' => 'red', + 'isBuilding' => false, + 'isComplete' => false, + ), + self::PENDING_ABORTING => array( + 'name' => pht('Aborting'), + 'icon' => 'fa-exclamation-triangle', + 'color' => 'red', + 'color.ansi' => 'red', + 'isBuilding' => false, + 'isComplete' => false, + ), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableActionController.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,299 +22,162 @@ return new Aphront404Response(); } - $issuable = array(); + $message = + HarbormasterBuildMessageTransaction::getTransactionObjectForMessageType( + $action); + if (!$message) { + return new Aphront404Response(); + } + + $return_uri = '/'.$buildable->getMonogram(); + + // See T13348. Actions may apply to only a subset of builds, so give the + // user a preview of what will happen. + + $can_send = array(); + $rows = array(); $builds = $buildable->getBuilds(); foreach ($builds as $key => $build) { - switch ($action) { - case HarbormasterBuildCommand::COMMAND_RESTART: - if ($build->canRestartBuild()) { - $issuable[$key] = $build; - } - break; - case HarbormasterBuildCommand::COMMAND_PAUSE: - if ($build->canPauseBuild()) { - $issuable[$key] = $build; - } - break; - case HarbormasterBuildCommand::COMMAND_RESUME: - if ($build->canResumeBuild()) { - $issuable[$key] = $build; - } - break; - case HarbormasterBuildCommand::COMMAND_ABORT: - if ($build->canAbortBuild()) { - $issuable[$key] = $build; - } - break; - default: - return new Aphront400Response(); + $exception = null; + try { + $message->assertCanSendMessage($viewer, $build); + $can_send[$key] = $build; + } catch (HarbormasterMessageException $ex) { + $exception = $ex; } - } - $restricted = false; - foreach ($issuable as $key => $build) { - if (!$build->canIssueCommand($viewer, $action)) { - $restricted = true; - unset($issuable[$key]); - } - } + if (!$exception) { + $icon_icon = $message->getIcon(); + $icon_color = 'green'; + + $title = $message->getHarbormasterBuildMessageName(); + $body = $message->getHarbormasterBuildableMessageEffect(); + } else { + $icon_icon = 'fa-times'; + $icon_color = 'red'; - $building = false; - foreach ($issuable as $key => $build) { - if ($build->isBuilding()) { - $building = true; - break; + $title = $ex->getTitle(); + $body = $ex->getBody(); } - } - $return_uri = '/'.$buildable->getMonogram(); - if ($request->isDialogFormPost() && $issuable) { + $icon = id(new PHUIIconView()) + ->setIcon($icon_icon) + ->setColor($icon_color); + + $build_name = phutil_tag( + 'a', + array( + 'href' => $build->getURI(), + 'target' => '_blank', + ), + pht('%s %s', $build->getObjectName(), $build->getName())); + + $rows[] = array( + $icon, + $build_name, + $title, + $body, + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + null, + pht('Build'), + pht('Action'), + pht('Details'), + )) + ->setColumnClasses( + array( + null, + null, + 'pri', + 'wide', + )); + + $table = phutil_tag( + 'div', + array( + 'class' => 'mlt mlb', + ), + $table); + + if ($request->isDialogFormPost() && $can_send) { $editor = id(new HarbormasterBuildableTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true); + $xaction_type = HarbormasterBuildableMessageTransaction::TRANSACTIONTYPE; + $xaction = id(new HarbormasterBuildableTransaction()) - ->setTransactionType(HarbormasterBuildableTransaction::TYPE_COMMAND) + ->setTransactionType($xaction_type) ->setNewValue($action); $editor->applyTransactions($buildable, array($xaction)); - $build_editor = id(new HarbormasterBuildTransactionEditor()) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true) - ->setContinueOnMissingFields(true); - - foreach ($issuable as $build) { - $xaction = id(new HarbormasterBuildTransaction()) - ->setTransactionType(HarbormasterBuildTransaction::TYPE_COMMAND) - ->setNewValue($action); - $build_editor->applyTransactions($build, array($xaction)); + foreach ($can_send as $build) { + $build->sendMessage( + $viewer, + $message->getHarbormasterBuildMessageType()); } return id(new AphrontRedirectResponse())->setURI($return_uri); } - $width = AphrontDialogView::WIDTH_DEFAULT; + if (!$builds) { + $title = pht('No Builds'); + $body = pht( + 'This buildable has no builds, so you can not issue any commands.'); + } else { + if ($can_send) { + $title = $message->newBuildableConfirmPromptTitle( + $builds, + $can_send); + + $body = $message->newBuildableConfirmPromptBody( + $builds, + $can_send); + } else { + $title = pht('Unable to Send Command'); + $body = pht( + 'You can not send this command to any of the current builds '. + 'for this buildable.'); + } - switch ($action) { - case HarbormasterBuildCommand::COMMAND_RESTART: - // See T13348. The "Restart Builds" action may restart only a subset - // of builds, so show the user a preview of which builds will actually - // restart. - - $body = array(); - - if ($issuable) { - $title = pht('Restart Builds'); - $submit = pht('Restart Builds'); - } else { - $title = pht('Unable to Restart Builds'); - } - - if ($builds) { - $width = AphrontDialogView::WIDTH_FORM; - - $body[] = pht('Builds for this buildable:'); - - $rows = array(); - foreach ($builds as $key => $build) { - if (isset($issuable[$key])) { - $icon = id(new PHUIIconView()) - ->setIcon('fa-repeat green'); - $build_note = pht('Will Restart'); - } else { - $icon = null; - - try { - $build->assertCanRestartBuild(); - } catch (HarbormasterRestartException $ex) { - $icon = id(new PHUIIconView()) - ->setIcon('fa-times red'); - $build_note = pht( - '%s: %s', - phutil_tag('strong', array(), pht('Not Restartable')), - $ex->getTitle()); - } - - if (!$icon) { - try { - $build->assertCanIssueCommand($viewer, $action); - } catch (PhabricatorPolicyException $ex) { - $icon = id(new PHUIIconView()) - ->setIcon('fa-lock red'); - $build_note = pht( - '%s: %s', - phutil_tag('strong', array(), pht('Not Restartable')), - pht('You do not have permission to restart this build.')); - } - } - - if (!$icon) { - $icon = id(new PHUIIconView()) - ->setIcon('fa-times red'); - $build_note = pht('Will Not Restart'); - } - } - - $build_name = phutil_tag( - 'a', - array( - 'href' => $build->getURI(), - 'target' => '_blank', - ), - pht('%s %s', $build->getObjectName(), $build->getName())); - - $rows[] = array( - $icon, - $build_name, - $build_note, - ); - } - - $table = id(new AphrontTableView($rows)) - ->setHeaders( - array( - null, - pht('Build'), - pht('Action'), - )) - ->setColumnClasses( - array( - null, - 'pri', - 'wide', - )); - - $table = phutil_tag( - 'div', - array( - 'class' => 'mlt mlb', - ), - $table); - - $body[] = $table; - } - - if ($issuable) { - $warnings = array(); - - if ($restricted) { - $warnings[] = pht( - 'You only have permission to restart some builds.'); - } - - if ($building) { - $warnings[] = pht( - 'Progress on running builds will be discarded.'); - } - - $warnings[] = pht( - 'When a build is restarted, side effects associated with '. - 'the build may occur again.'); - - $body[] = id(new PHUIInfoView()) - ->setSeverity(PHUIInfoView::SEVERITY_WARNING) - ->setErrors($warnings); - - $body[] = pht('Really restart builds?'); - } else { - if ($restricted) { - $body[] = pht('You do not have permission to restart any builds.'); - } else { - $body[] = pht('No builds can be restarted.'); - } - } - - break; - case HarbormasterBuildCommand::COMMAND_PAUSE: - if ($issuable) { - $title = pht('Really pause builds?'); - - if ($restricted) { - $body = pht( - 'You only have permission to pause some builds. Once the '. - 'current steps complete, work will halt on builds you have '. - 'permission to pause. You can resume the builds later.'); - } else { - $body = pht( - 'If you pause all builds, work will halt once the current steps '. - 'complete. You can resume the builds later.'); - } - $submit = pht('Pause Builds'); - } else { - $title = pht('Unable to Pause Builds'); - - if ($restricted) { - $body = pht('You do not have permission to pause any builds.'); - } else { - $body = pht('No builds can be paused.'); - } - } - break; - case HarbormasterBuildCommand::COMMAND_ABORT: - if ($issuable) { - $title = pht('Really abort builds?'); - if ($restricted) { - $body = pht( - 'You only have permission to abort some builds. Work will '. - 'halt immediately on builds you have permission to abort. '. - 'Progress will be discarded, and builds must be completely '. - 'restarted if you want them to complete.'); - } else { - $body = pht( - 'If you abort all builds, work will halt immediately. Work '. - 'will be discarded, and builds must be completely restarted.'); - } - $submit = pht('Abort Builds'); - } else { - $title = pht('Unable to Abort Builds'); - - if ($restricted) { - $body = pht('You do not have permission to abort any builds.'); - } else { - $body = pht('No builds can be aborted.'); - } - } - break; - case HarbormasterBuildCommand::COMMAND_RESUME: - if ($issuable) { - $title = pht('Really resume builds?'); - if ($restricted) { - $body = pht( - 'You only have permission to resume some builds. Work will '. - 'continue on builds you have permission to resume.'); - } else { - $body = pht('Work will continue on all builds. Really resume?'); - } - - $submit = pht('Resume Builds'); - } else { - $title = pht('Unable to Resume Builds'); - if ($restricted) { - $body = pht('You do not have permission to resume any builds.'); - } else { - $body = pht('No builds can be resumed.'); - } - } - break; + $body = array( + pht('Builds for this buildable:'), + $table, + $body, + ); } - $dialog = id(new AphrontDialogView()) - ->setUser($viewer) - ->setWidth($width) + $warnings = $message->newBuildableConfirmPromptWarnings( + $builds, + $can_send); + + if ($warnings) { + $body[] = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_WARNING) + ->setErrors($warnings); + } + + $submit = $message->getHarbormasterBuildableMessageName(); + + $dialog = $this->newDialog() + ->setWidth(AphrontDialogView::WIDTH_FULL) ->setTitle($title) ->appendChild($body) ->addCancelButton($return_uri); - if ($issuable) { + if ($can_send) { $dialog->addSubmitButton($submit); } - return id(new AphrontDialogResponse())->setDialog($dialog); + return $dialog; } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildableViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -87,75 +87,39 @@ $buildable, PhabricatorPolicyCapability::CAN_EDIT); - $can_restart = false; - $can_resume = false; - $can_pause = false; - $can_abort = false; - - $command_restart = HarbormasterBuildCommand::COMMAND_RESTART; - $command_resume = HarbormasterBuildCommand::COMMAND_RESUME; - $command_pause = HarbormasterBuildCommand::COMMAND_PAUSE; - $command_abort = HarbormasterBuildCommand::COMMAND_ABORT; - - foreach ($buildable->getBuilds() as $build) { - if ($build->canRestartBuild()) { - if ($build->canIssueCommand($viewer, $command_restart)) { - $can_restart = true; - } - } - if ($build->canResumeBuild()) { - if ($build->canIssueCommand($viewer, $command_resume)) { - $can_resume = true; - } - } - if ($build->canPauseBuild()) { - if ($build->canIssueCommand($viewer, $command_pause)) { - $can_pause = true; - } - } - if ($build->canAbortBuild()) { - if ($build->canIssueCommand($viewer, $command_abort)) { - $can_abort = true; + $messages = array( + new HarbormasterBuildMessageRestartTransaction(), + new HarbormasterBuildMessagePauseTransaction(), + new HarbormasterBuildMessageResumeTransaction(), + new HarbormasterBuildMessageAbortTransaction(), + ); + + foreach ($messages as $message) { + + // Messages are enabled if they can be sent to at least one build. + $can_send = false; + foreach ($buildable->getBuilds() as $build) { + $can_send = $message->canSendMessage($viewer, $build); + if ($can_send) { + break; } } - } - $restart_uri = "buildable/{$id}/restart/"; - $pause_uri = "buildable/{$id}/pause/"; - $resume_uri = "buildable/{$id}/resume/"; - $abort_uri = "buildable/{$id}/abort/"; - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-repeat') - ->setName(pht('Restart Builds')) - ->setHref($this->getApplicationURI($restart_uri)) - ->setWorkflow(true) - ->setDisabled(!$can_restart || !$can_edit)); - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pause') - ->setName(pht('Pause Builds')) - ->setHref($this->getApplicationURI($pause_uri)) - ->setWorkflow(true) - ->setDisabled(!$can_pause || !$can_edit)); - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-play') - ->setName(pht('Resume Builds')) - ->setHref($this->getApplicationURI($resume_uri)) - ->setWorkflow(true) - ->setDisabled(!$can_resume || !$can_edit)); - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-exclamation-triangle') - ->setName(pht('Abort Builds')) - ->setHref($this->getApplicationURI($abort_uri)) - ->setWorkflow(true) - ->setDisabled(!$can_abort || !$can_edit)); + $message_uri = urisprintf( + '/buildable/%d/%s/', + $id, + $message->getHarbormasterBuildMessageType()); + $message_uri = $this->getApplicationURI($message_uri); + + $action = id(new PhabricatorActionView()) + ->setName($message->getHarbormasterBuildableMessageName()) + ->setIcon($message->getIcon()) + ->setHref($message_uri) + ->setDisabled(!$can_send || !$can_edit) + ->setWorkflow(true); + + $curtain->addAction($action); + } return $curtain; } @@ -198,56 +162,17 @@ ->setUser($viewer); foreach ($buildable->getBuilds() as $build) { $view_uri = $this->getApplicationURI('/build/'.$build->getID().'/'); + $item = id(new PHUIObjectItemView()) ->setObjectName(pht('Build %d', $build->getID())) ->setHeader($build->getName()) ->setHref($view_uri); - $status = $build->getBuildStatus(); - $status_color = HarbormasterBuildStatus::getBuildStatusColor($status); - $status_name = HarbormasterBuildStatus::getBuildStatusName($status); - $item->setStatusIcon('fa-dot-circle-o '.$status_color, $status_name); - $item->addAttribute($status_name); - - if ($build->isRestarting()) { - $item->addIcon('fa-repeat', pht('Restarting')); - } else if ($build->isPausing()) { - $item->addIcon('fa-pause', pht('Pausing')); - } else if ($build->isResuming()) { - $item->addIcon('fa-play', pht('Resuming')); - } - - $build_id = $build->getID(); + $status = $build->getBuildPendingStatusObject(); - $restart_uri = "build/restart/{$build_id}/buildable/"; - $resume_uri = "build/resume/{$build_id}/buildable/"; - $pause_uri = "build/pause/{$build_id}/buildable/"; - $abort_uri = "build/abort/{$build_id}/buildable/"; - - $item->addAction( - id(new PHUIListItemView()) - ->setIcon('fa-repeat') - ->setName(pht('Restart')) - ->setHref($this->getApplicationURI($restart_uri)) - ->setWorkflow(true) - ->setDisabled(!$build->canRestartBuild())); - - if ($build->canResumeBuild()) { - $item->addAction( - id(new PHUIListItemView()) - ->setIcon('fa-play') - ->setName(pht('Resume')) - ->setHref($this->getApplicationURI($resume_uri)) - ->setWorkflow(true)); - } else { - $item->addAction( - id(new PHUIListItemView()) - ->setIcon('fa-pause') - ->setName(pht('Pause')) - ->setHref($this->getApplicationURI($pause_uri)) - ->setWorkflow(true) - ->setDisabled(!$build->canPauseBuild())); - } + $item->setStatusIcon( + $status->getIconIcon().' '.$status->getIconColor(), + $status->getName()); $targets = $build->getBuildTargets(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildActionController.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildActionController.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildActionController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildActionController.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,24 +22,13 @@ return new Aphront404Response(); } - switch ($action) { - case HarbormasterBuildCommand::COMMAND_RESTART: - $can_issue = $build->canRestartBuild(); - break; - case HarbormasterBuildCommand::COMMAND_PAUSE: - $can_issue = $build->canPauseBuild(); - break; - case HarbormasterBuildCommand::COMMAND_RESUME: - $can_issue = $build->canResumeBuild(); - break; - case HarbormasterBuildCommand::COMMAND_ABORT: - $can_issue = $build->canAbortBuild(); - break; - default: - return new Aphront400Response(); - } + $xaction = + HarbormasterBuildMessageTransaction::getTransactionObjectForMessageType( + $action); - $build->assertCanIssueCommand($viewer, $action); + if (!$xaction) { + return new Aphront404Response(); + } switch ($via) { case 'buildable': @@ -50,100 +39,29 @@ break; } - if ($request->isDialogFormPost() && $can_issue) { - $build->sendMessage($viewer, $action); - return id(new AphrontRedirectResponse())->setURI($return_uri); + try { + $xaction->assertCanSendMessage($viewer, $build); + } catch (HarbormasterMessageException $ex) { + return $this->newDialog() + ->setTitle($ex->getTitle()) + ->appendChild($ex->getBody()) + ->addCancelButton($return_uri); } - switch ($action) { - case HarbormasterBuildCommand::COMMAND_RESTART: - if ($can_issue) { - $title = pht('Really restart build?'); - $body = pht( - 'Progress on this build will be discarded and the build will '. - 'restart. Side effects of the build will occur again. Really '. - 'restart build?'); - $submit = pht('Restart Build'); - } else { - try { - $build->assertCanRestartBuild(); - throw new Exception(pht('Expected to be unable to restart build.')); - } catch (HarbormasterRestartException $ex) { - $title = $ex->getTitle(); - $body = $ex->getBody(); - } - } - break; - case HarbormasterBuildCommand::COMMAND_ABORT: - if ($can_issue) { - $title = pht('Really abort build?'); - $body = pht( - 'Progress on this build will be discarded. Really '. - 'abort build?'); - $submit = pht('Abort Build'); - } else { - $title = pht('Unable to Abort Build'); - $body = pht('You can not abort this build.'); - } - break; - case HarbormasterBuildCommand::COMMAND_PAUSE: - if ($can_issue) { - $title = pht('Really pause build?'); - $body = pht( - 'If you pause this build, work will halt once the current steps '. - 'complete. You can resume the build later.'); - $submit = pht('Pause Build'); - } else { - $title = pht('Unable to Pause Build'); - if ($build->isComplete()) { - $body = pht( - 'This build is already complete. You can not pause a completed '. - 'build.'); - } else if ($build->isPaused()) { - $body = pht( - 'This build is already paused. You can not pause a build which '. - 'has already been paused.'); - } else if ($build->isPausing()) { - $body = pht( - 'This build is already pausing. You can not reissue a pause '. - 'command to a pausing build.'); - } else { - $body = pht( - 'This build can not be paused.'); - } - } - break; - case HarbormasterBuildCommand::COMMAND_RESUME: - if ($can_issue) { - $title = pht('Really resume build?'); - $body = pht( - 'Work will continue on the build. Really resume?'); - $submit = pht('Resume Build'); - } else { - $title = pht('Unable to Resume Build'); - if ($build->isResuming()) { - $body = pht( - 'This build is already resuming. You can not reissue a resume '. - 'command to a resuming build.'); - } else if (!$build->isPaused()) { - $body = pht( - 'This build is not paused. You can only resume a paused '. - 'build.'); - } - } - break; + if ($request->isDialogFormPost()) { + $build->sendMessage($viewer, $xaction->getHarbormasterBuildMessageType()); + return id(new AphrontRedirectResponse())->setURI($return_uri); } - $dialog = $this->newDialog() + $title = $xaction->newConfirmPromptTitle(); + $body = $xaction->newConfirmPromptBody(); + $submit = $xaction->getHarbormasterBuildMessageName(); + + return $this->newDialog() ->setTitle($title) ->appendChild($body) - ->addCancelButton($return_uri); - - if ($can_issue) { - $dialog->addSubmitButton($submit); - } - - return $dialog; + ->addCancelButton($return_uri) + ->addSubmitButton($submit); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildViewController.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildViewController.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterBuildViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterBuildViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,21 +32,13 @@ ->setPolicyObject($build) ->setHeaderIcon('fa-cubes'); - $is_restarting = $build->isRestarting(); + $status = $build->getBuildPendingStatusObject(); - if ($is_restarting) { - $page_header->setStatus( - 'fa-exclamation-triangle', 'red', pht('Restarting')); - } else if ($build->isPausing()) { - $page_header->setStatus( - 'fa-exclamation-triangle', 'red', pht('Pausing')); - } else if ($build->isResuming()) { - $page_header->setStatus( - 'fa-exclamation-triangle', 'red', pht('Resuming')); - } else if ($build->isAborting()) { - $page_header->setStatus( - 'fa-exclamation-triangle', 'red', pht('Aborting')); - } + $status_icon = $status->getIconIcon(); + $status_color = $status->getIconColor(); + $status_name = $status->getName(); + + $page_header->setStatus($status_icon, $status_color, $status_name); $max_generation = (int)$build->getBuildGeneration(); if ($max_generation === 0) { @@ -55,7 +47,7 @@ $min_generation = 1; } - if ($is_restarting) { + if ($build->isRestarting()) { $max_generation = $max_generation + 1; } @@ -541,63 +533,31 @@ $curtain = $this->newCurtainView($build); - $can_restart = - $build->canRestartBuild() && - $build->canIssueCommand( - $viewer, - HarbormasterBuildCommand::COMMAND_RESTART); - - $can_pause = - $build->canPauseBuild() && - $build->canIssueCommand( - $viewer, - HarbormasterBuildCommand::COMMAND_PAUSE); - - $can_resume = - $build->canResumeBuild() && - $build->canIssueCommand( - $viewer, - HarbormasterBuildCommand::COMMAND_RESUME); - - $can_abort = - $build->canAbortBuild() && - $build->canIssueCommand( - $viewer, - HarbormasterBuildCommand::COMMAND_ABORT); - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Restart Build')) - ->setIcon('fa-repeat') - ->setHref($this->getApplicationURI('/build/restart/'.$id.'/')) - ->setDisabled(!$can_restart) - ->setWorkflow(true)); - - if ($build->canResumeBuild()) { - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Resume Build')) - ->setIcon('fa-play') - ->setHref($this->getApplicationURI('/build/resume/'.$id.'/')) - ->setDisabled(!$can_resume) - ->setWorkflow(true)); - } else { - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Pause Build')) - ->setIcon('fa-pause') - ->setHref($this->getApplicationURI('/build/pause/'.$id.'/')) - ->setDisabled(!$can_pause) - ->setWorkflow(true)); - } - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Abort Build')) - ->setIcon('fa-exclamation-triangle') - ->setHref($this->getApplicationURI('/build/abort/'.$id.'/')) - ->setDisabled(!$can_abort) - ->setWorkflow(true)); + $messages = array( + new HarbormasterBuildMessageRestartTransaction(), + new HarbormasterBuildMessagePauseTransaction(), + new HarbormasterBuildMessageResumeTransaction(), + new HarbormasterBuildMessageAbortTransaction(), + ); + + foreach ($messages as $message) { + $can_send = $message->canSendMessage($viewer, $build); + + $message_uri = urisprintf( + '/build/%s/%d/', + $message->getHarbormasterBuildMessageType(), + $id); + $message_uri = $this->getApplicationURI($message_uri); + + $action = id(new PhabricatorActionView()) + ->setName($message->getHarbormasterBuildMessageName()) + ->setIcon($message->getIcon()) + ->setHref($message_uri) + ->setDisabled(!$can_send) + ->setWorkflow(true); + + $curtain->addAction($action); + } return $curtain; } @@ -624,10 +584,6 @@ pht('Build Plan'), $handles[$build->getBuildPlanPHID()]->renderLink()); - $properties->addProperty( - pht('Status'), - $this->getStatus($build)); - return id(new PHUIObjectBoxView()) ->setHeaderText(pht('Properties')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) @@ -681,31 +637,6 @@ ->setTable($table); } - - private function getStatus(HarbormasterBuild $build) { - $status_view = new PHUIStatusListView(); - - $item = new PHUIStatusItemView(); - - if ($build->isPausing()) { - $status_name = pht('Pausing'); - $icon = PHUIStatusItemView::ICON_RIGHT; - $color = 'dark'; - } else { - $status = $build->getBuildStatus(); - $status_name = - HarbormasterBuildStatus::getBuildStatusName($status); - $icon = HarbormasterBuildStatus::getBuildStatusIcon($status); - $color = HarbormasterBuildStatus::getBuildStatusColor($status); - } - - $item->setTarget($status_name); - $item->setIcon($icon, $color); - $status_view->addItem($item); - - return $status_view; - } - private function buildMessages(array $messages) { $viewer = $this->getRequest()->getUser(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterPlanRunController.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterPlanRunController.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/controller/HarbormasterPlanRunController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/controller/HarbormasterPlanRunController.php 2022-06-14 16:29:55.000000000 +0000 @@ -84,7 +84,7 @@ "example, `rX123456` or `D123`).\n\n". "For more detailed output, you can also run manual builds from ". "the command line:\n\n". - " phabricator/ $ ./bin/harbormaster build <object> --plan %s", + " $ ./bin/harbormaster build <object> --plan %s", $plan->getID())) ->appendChild( id(new AphrontFormTextControl()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php 2022-06-14 16:29:55.000000000 +0000 @@ -30,8 +30,8 @@ 'After completing this build step Harbormaster can continue the '. 'build normally, or it can pause the build and wait for a message. '. 'If you are using this build step to trigger some work in an '. - 'external system, you may want to have Phabricator wait for that '. - 'system to perform the work and report results back.'. + 'external system, you may want wait for that system to perform '. + 'the work and report results back.'. "\n\n". 'If you select **Continue Build Normally**, the build plan will '. 'proceed once this step finishes.'. diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableEditEngine.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableEditEngine.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,84 @@ +<?php + +final class HarbormasterBuildableEditEngine + extends PhabricatorEditEngine { + + const ENGINECONST = 'harbormaster.buildable'; + + public function isEngineConfigurable() { + return false; + } + + public function getEngineName() { + return pht('Harbormaster Buildables'); + } + + public function getSummaryHeader() { + return pht('Edit Harbormaster Buildable Configurations'); + } + + public function getSummaryText() { + return pht('This engine is used to edit Harbormaster buildables.'); + } + + public function getEngineApplicationClass() { + return 'PhabricatorHarbormasterApplication'; + } + + protected function newEditableObject() { + $viewer = $this->getViewer(); + return HarbormasterBuildable::initializeNewBuildable($viewer); + } + + protected function newObjectQuery() { + return new HarbormasterBuildableQuery(); + } + + protected function newEditableObjectForDocumentation() { + $object = new DifferentialRevision(); + + return $this->newEditableObject() + ->attachBuildableObject($object); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create Buildable'); + } + + protected function getObjectCreateButtonText($object) { + return pht('Create Buildable'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit Buildable: %s', $object->getName()); + } + + protected function getObjectEditShortText($object) { + return pht('Edit Buildable'); + } + + protected function getObjectCreateShortText() { + return pht('Create Buildable'); + } + + protected function getObjectName() { + return pht('Buildable'); + } + + protected function getEditorURI() { + return '/harbormaster/buildable/edit/'; + } + + protected function getObjectCreateCancelURI($object) { + return '/harbormaster/'; + } + + protected function getObjectViewURI($object) { + return $object->getURI(); + } + + protected function buildCustomEditFields($object) { + return array(); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,66 +11,4 @@ return pht('Harbormaster Buildables'); } - public function getTransactionTypes() { - $types = parent::getTransactionTypes(); - - $types[] = HarbormasterBuildableTransaction::TYPE_CREATE; - $types[] = HarbormasterBuildableTransaction::TYPE_COMMAND; - - return $types; - } - - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildableTransaction::TYPE_CREATE: - case HarbormasterBuildableTransaction::TYPE_COMMAND: - return null; - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildableTransaction::TYPE_CREATE: - return true; - case HarbormasterBuildableTransaction::TYPE_COMMAND: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildableTransaction::TYPE_CREATE: - case HarbormasterBuildableTransaction::TYPE_COMMAND: - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildableTransaction::TYPE_CREATE: - case HarbormasterBuildableTransaction::TYPE_COMMAND: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildEditEngine.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildEditEngine.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,87 @@ +<?php + +final class HarbormasterBuildEditEngine + extends PhabricatorEditEngine { + + const ENGINECONST = 'harbormaster.build'; + + public function isEngineConfigurable() { + return false; + } + + public function getEngineName() { + return pht('Harbormaster Builds'); + } + + public function getSummaryHeader() { + return pht('Edit Harbormaster Build Configurations'); + } + + public function getSummaryText() { + return pht('This engine is used to edit Harbormaster builds.'); + } + + public function getEngineApplicationClass() { + return 'PhabricatorHarbormasterApplication'; + } + + protected function newEditableObject() { + $viewer = $this->getViewer(); + return HarbormasterBuild::initializeNewBuild($viewer); + } + + protected function newObjectQuery() { + return new HarbormasterBuildQuery(); + } + + protected function newEditableObjectForDocumentation() { + $object = new DifferentialRevision(); + + $buildable = id(new HarbormasterBuildable()) + ->attachBuildableObject($object); + + return $this->newEditableObject() + ->attachBuildable($buildable); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create Build'); + } + + protected function getObjectCreateButtonText($object) { + return pht('Create Build'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit Build: %s', $object->getName()); + } + + protected function getObjectEditShortText($object) { + return pht('Edit Build'); + } + + protected function getObjectCreateShortText() { + return pht('Create Build'); + } + + protected function getObjectName() { + return pht('Build'); + } + + protected function getEditorURI() { + return '/harbormaster/build/edit/'; + } + + protected function getObjectCreateCancelURI($object) { + return '/harbormaster/'; + } + + protected function getObjectViewURI($object) { + return $object->getURI(); + } + + protected function buildCustomEditFields($object) { + return array(); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildStepEditEngine.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildStepEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildStepEditEngine.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildStepEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,107 @@ +<?php + +final class HarbormasterBuildStepEditEngine + extends PhabricatorEditEngine { + + const ENGINECONST = 'harbormaster.buildstep'; + + private $buildPlan; + + public function setBuildPlan(HarbormasterBuildPlan $build_plan) { + $this->buildPlan = $build_plan; + return $this; + } + + public function getBuildPlan() { + if ($this->buildPlan === null) { + throw new PhutilInvalidStateException('setBuildPlan'); + } + + return $this->buildPlan; + } + + public function isEngineConfigurable() { + return false; + } + + public function getEngineName() { + return pht('Harbormaster Build Steps'); + } + + public function getSummaryHeader() { + return pht('Edit Harbormaster Build Step Configurations'); + } + + public function getSummaryText() { + return pht('This engine is used to edit Harbormaster build steps.'); + } + + public function getEngineApplicationClass() { + return 'PhabricatorHarbormasterApplication'; + } + + protected function newEditableObject() { + $viewer = $this->getViewer(); + + + $plan = HarbormasterBuildPlan::initializeNewBuildPlan($viewer); + $this->setBuildPlan($plan); + + $plan = $this->getBuildPlan(); + + $step = HarbormasterBuildStep::initializeNewStep($viewer); + + $step->setBuildPlanPHID($plan->getPHID()); + $step->attachBuildPlan($plan); + + return $step; + } + + protected function newObjectQuery() { + return new HarbormasterBuildStepQuery(); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create Build Step'); + } + + protected function getObjectCreateButtonText($object) { + return pht('Create Build Step'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit Build Step: %s', $object->getName()); + } + + protected function getObjectEditShortText($object) { + return pht('Edit Build Step'); + } + + protected function getObjectCreateShortText() { + return pht('Create Build Step'); + } + + protected function getObjectName() { + return pht('Build Step'); + } + + protected function getEditorURI() { + return '/harbormaster/step/edit/'; + } + + protected function getObjectCreateCancelURI($object) { + return '/harbormaster/step/'; + } + + protected function getObjectViewURI($object) { + $id = $object->getID(); + return "/harbormaster/step/{$id}/"; + } + + protected function buildCustomEditFields($object) { + $fields = array(); + + return $fields; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,115 +11,4 @@ return pht('Harbormaster Builds'); } - public function getTransactionTypes() { - $types = parent::getTransactionTypes(); - - $types[] = HarbormasterBuildTransaction::TYPE_CREATE; - $types[] = HarbormasterBuildTransaction::TYPE_COMMAND; - - return $types; - } - - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildTransaction::TYPE_CREATE: - case HarbormasterBuildTransaction::TYPE_COMMAND: - return null; - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildTransaction::TYPE_CREATE: - return true; - case HarbormasterBuildTransaction::TYPE_COMMAND: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildTransaction::TYPE_CREATE: - return; - case HarbormasterBuildTransaction::TYPE_COMMAND: - return $this->executeBuildCommand($object, $xaction); - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - private function executeBuildCommand( - HarbormasterBuild $build, - HarbormasterBuildTransaction $xaction) { - - $command = $xaction->getNewValue(); - - switch ($command) { - case HarbormasterBuildCommand::COMMAND_RESTART: - $issuable = $build->canRestartBuild(); - break; - case HarbormasterBuildCommand::COMMAND_PAUSE: - $issuable = $build->canPauseBuild(); - break; - case HarbormasterBuildCommand::COMMAND_RESUME: - $issuable = $build->canResumeBuild(); - break; - case HarbormasterBuildCommand::COMMAND_ABORT: - $issuable = $build->canAbortBuild(); - break; - default: - throw new Exception(pht('Unknown command %s', $command)); - } - - if (!$issuable) { - return; - } - - $actor = $this->getActor(); - if (!$build->canIssueCommand($actor, $command)) { - return; - } - - id(new HarbormasterBuildCommand()) - ->setAuthorPHID($xaction->getAuthorPHID()) - ->setTargetPHID($build->getPHID()) - ->setCommand($command) - ->save(); - - PhabricatorWorker::scheduleTask( - 'HarbormasterBuildWorker', - array( - 'buildID' => $build->getID(), - ), - array( - 'objectPHID' => $build->getPHID(), - )); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case HarbormasterBuildTransaction::TYPE_CREATE: - case HarbormasterBuildTransaction::TYPE_COMMAND: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/engine/HarbormasterBuildEngine.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/engine/HarbormasterBuildEngine.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/engine/HarbormasterBuildEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/engine/HarbormasterBuildEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -49,6 +49,7 @@ } public function continueBuild() { + $viewer = $this->getViewer(); $build = $this->getBuild(); $lock_key = 'harbormaster.build:'.$build->getID(); @@ -68,7 +69,7 @@ $lock->unlock(); - $this->releaseAllArtifacts($build); + $build->releaseAllArtifacts($viewer); throw $ex; } @@ -99,56 +100,66 @@ // If we are no longer building for any reason, release all artifacts. if (!$build->isBuilding()) { - $this->releaseAllArtifacts($build); + $build->releaseAllArtifacts($viewer); } } private function updateBuild(HarbormasterBuild $build) { - if ($build->isAborting()) { - $this->releaseAllArtifacts($build); - $build->setBuildStatus(HarbormasterBuildStatus::STATUS_ABORTED); - $build->save(); - } + $viewer = $this->getViewer(); - if (($build->getBuildStatus() == HarbormasterBuildStatus::STATUS_PENDING) || - ($build->isRestarting())) { - $this->restartBuild($build); - $build->setBuildStatus(HarbormasterBuildStatus::STATUS_BUILDING); - $build->save(); - } + $content_source = PhabricatorContentSource::newForSource( + PhabricatorDaemonContentSource::SOURCECONST); - if ($build->isResuming()) { - $build->setBuildStatus(HarbormasterBuildStatus::STATUS_BUILDING); - $build->save(); + $acting_phid = $viewer->getPHID(); + if (!$acting_phid) { + $acting_phid = id(new PhabricatorHarbormasterApplication())->getPHID(); } - if ($build->isPausing() && !$build->isComplete()) { - $build->setBuildStatus(HarbormasterBuildStatus::STATUS_PAUSED); - $build->save(); - } + $editor = $build->getApplicationTransactionEditor() + ->setActor($viewer) + ->setActingAsPHID($acting_phid) + ->setContentSource($content_source) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); - $build->deleteUnprocessedCommands(); + $xactions = array(); - if ($build->getBuildStatus() == HarbormasterBuildStatus::STATUS_BUILDING) { - $this->updateBuildSteps($build); - } - } + $messages = $build->getUnprocessedMessagesForApply(); + foreach ($messages as $message) { + $message_type = $message->getType(); - private function restartBuild(HarbormasterBuild $build) { + $message_xaction = + HarbormasterBuildMessageTransaction::getTransactionTypeForMessageType( + $message_type); - // We're restarting the build, so release all previous artifacts. - $this->releaseAllArtifacts($build); + if (!$message_xaction) { + continue; + } - // Increment the build generation counter on the build. - $build->setBuildGeneration($build->getBuildGeneration() + 1); + $xactions[] = $build->getApplicationTransactionTemplate() + ->setAuthorPHID($message->getAuthorPHID()) + ->setTransactionType($message_xaction) + ->setNewValue($message_type); + } - // Currently running targets should periodically check their build - // generation (which won't have changed) against the build's generation. - // If it is different, they will automatically stop what they're doing - // and abort. + if (!$xactions) { + if ($build->isPending()) { + // TODO: This should be a transaction. - // Previously we used to delete targets, logs and artifacts here. Instead, - // leave them around so users can view previous generations of this build. + $build->restartBuild($viewer); + $build->setBuildStatus(HarbormasterBuildStatus::STATUS_BUILDING); + $build->save(); + } + } + + if ($xactions) { + $editor->applyTransactions($build, $xactions); + $build->markUnprocessedMessagesAsProcessed(); + } + + if ($build->getBuildStatus() == HarbormasterBuildStatus::STATUS_BUILDING) { + $this->updateBuildSteps($build); + } } private function updateBuildSteps(HarbormasterBuild $build) { @@ -596,29 +607,6 @@ ->publishBuildable($old, $new); } - private function releaseAllArtifacts(HarbormasterBuild $build) { - $targets = id(new HarbormasterBuildTargetQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withBuildPHIDs(array($build->getPHID())) - ->withBuildGenerations(array($build->getBuildGeneration())) - ->execute(); - - if (count($targets) === 0) { - return; - } - - $target_phids = mpull($targets, 'getPHID'); - - $artifacts = id(new HarbormasterBuildArtifactQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withBuildTargetPHIDs($target_phids) - ->withIsReleased(false) - ->execute(); - foreach ($artifacts as $artifact) { - $artifact->releaseArtifact(); - } - } - private function releaseQueuedArtifacts() { foreach ($this->artifactReleaseQueue as $key => $artifact) { $artifact->releaseArtifact(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/exception/HarbormasterMessageException.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/exception/HarbormasterMessageException.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/exception/HarbormasterMessageException.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/exception/HarbormasterMessageException.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,46 @@ +<?php + +final class HarbormasterMessageException extends Exception { + + private $title; + private $body = array(); + + public function __construct($title, $body = null) { + $this->setTitle($title); + $this->appendParagraph($body); + + parent::__construct( + pht( + '%s: %s', + $title, + $body)); + } + + public function setTitle($title) { + $this->title = $title; + return $this; + } + + public function getTitle() { + return $this->title; + } + + public function appendParagraph($description) { + $this->body[] = $description; + return $this; + } + + public function getBody() { + return $this->body; + } + + public function newDisplayString() { + $title = $this->getTitle(); + + $body = $this->getBody(); + $body = implode("\n\n", $body); + + return pht('%s: %s', $title, $body); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/exception/HarbormasterRestartException.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/exception/HarbormasterRestartException.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/exception/HarbormasterRestartException.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/exception/HarbormasterRestartException.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -<?php - -final class HarbormasterRestartException extends Exception { - - private $title; - private $body = array(); - - public function __construct($title, $body = null) { - $this->setTitle($title); - $this->appendParagraph($body); - - parent::__construct($title); - } - - public function setTitle($title) { - $this->title = $title; - return $this; - } - - public function getTitle() { - return $this->title; - } - - public function appendParagraph($description) { - $this->body[] = $description; - return $this; - } - - public function getBody() { - return $this->body; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,10 @@ if (!$ids && !$active) { throw new PhutilArgumentUsageException( - pht('Use --id or --active to select builds.')); + pht('Use "--id" or "--active" to select builds.')); } if ($ids && $active) { throw new PhutilArgumentUsageException( - pht('Use one of --id or --active to select builds, but not both.')); + pht('Use one of "--id" or "--active" to select builds, but not both.')); } $query = id(new HarbormasterBuildQuery()) @@ -48,50 +48,41 @@ } $builds = $query->execute(); - $console = PhutilConsole::getConsole(); $count = count($builds); if (!$count) { - $console->writeOut("%s\n", pht('No builds to restart.')); + $this->logSkip( + pht('SKIP'), + pht('No builds to restart.')); return 0; } + $prompt = pht('Restart %s build(s)?', new PhutilNumber($count)); if (!phutil_console_confirm($prompt)) { - $console->writeOut("%s\n", pht('Cancelled.')); - return 1; + throw new ArcanistUserAbortException(); } - $app_phid = id(new PhabricatorHarbormasterApplication())->getPHID(); - $editor = id(new HarbormasterBuildTransactionEditor()) - ->setActor($viewer) - ->setActingAsPHID($app_phid) - ->setContentSource($this->newContentSource()); + $message = new HarbormasterBuildMessageRestartTransaction(); + foreach ($builds as $build) { - $console->writeOut( - "<bg:blue> %s </bg> %s\n", + $this->logInfo( pht('RESTARTING'), pht('Build %d: %s', $build->getID(), $build->getName())); - if (!$build->canRestartBuild()) { - $console->writeOut( - "<bg:yellow> %s </bg> %s\n", - pht('INVALID'), - pht('Cannot be restarted.')); - continue; - } - $xactions = array(); - $xactions[] = id(new HarbormasterBuildTransaction()) - ->setTransactionType(HarbormasterBuildTransaction::TYPE_COMMAND) - ->setNewValue(HarbormasterBuildCommand::COMMAND_RESTART); + try { - $editor->applyTransactions($build, $xactions); - } catch (Exception $e) { - $message = phutil_console_wrap($e->getMessage(), 2); - $console->writeOut( - "<bg:red> %s </bg>\n%s\n", - pht('FAILED'), - $message); - continue; + $message->assertCanSendMessage($viewer, $build); + } catch (HarbormasterMessageException $ex) { + $this->logWarn( + pht('INVALID'), + $ex->newDisplayString()); } - $console->writeOut("<bg:green> %s </bg>\n", pht('SUCCESS')); + + $build->sendMessage( + $viewer, + $message->getHarbormasterBuildMessageType()); + + $this->logOkay( + pht('QUEUED'), + pht('Sent a restart message to build.')); } return 0; diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildableQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildableQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildableQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildableQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -63,10 +63,6 @@ return new HarbormasterBuildable(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { $buildables = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildArtifactQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildArtifactQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildArtifactQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildArtifactQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,10 +40,6 @@ return new HarbormasterBuildArtifact(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { $build_targets = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -27,10 +27,6 @@ return new HarbormasterBuildLog(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { $build_targets = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildMessageQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildMessageQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildMessageQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildMessageQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new HarbormasterBuildMessage(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { $receiver_phids = array_filter(mpull($page, 'getReceiverPHID')); if ($receiver_phids) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildPlanQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildPlanQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildPlanQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildPlanQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -50,10 +50,6 @@ return new HarbormasterBuildPlan(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function didFilterPage(array $page) { if ($this->needBuildSteps) { $plan_phids = mpull($page, 'getPHID'); @@ -98,7 +94,7 @@ $this->statuses); } - if (strlen($this->datasourceQuery)) { + if (!phutil_nonempty_string($this->datasourceQuery)) { $where[] = qsprintf( $conn, 'plan.name LIKE %>', diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -56,10 +56,6 @@ return new HarbormasterBuild(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { $buildables = array(); @@ -104,13 +100,13 @@ } $build_phids = mpull($page, 'getPHID'); - $commands = id(new HarbormasterBuildCommand())->loadAllWhere( - 'targetPHID IN (%Ls) ORDER BY id ASC', + $messages = id(new HarbormasterBuildMessage())->loadAllWhere( + 'receiverPHID IN (%Ls) AND isConsumed = 0 ORDER BY id ASC', $build_phids); - $commands = mgroup($commands, 'getTargetPHID'); + $messages = mgroup($messages, 'getReceiverPHID'); foreach ($page as $build) { - $unprocessed_commands = idx($commands, $build->getPHID(), array()); - $build->attachUnprocessedCommands($unprocessed_commands); + $unprocessed_messages = idx($messages, $build->getPHID(), array()); + $build->attachUnprocessedMessages($unprocessed_messages); } if ($this->needBuildTargets) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new HarbormasterBuildStep(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepSearchEngine.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildStepSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,58 @@ +<?php + +final class HarbormasterBuildStepSearchEngine + extends PhabricatorApplicationSearchEngine { + + public function getResultTypeDescription() { + return pht('Harbormaster Build Steps'); + } + + public function getApplicationClassName() { + return 'PhabricatorHarbormasterApplication'; + } + + public function newQuery() { + return new HarbormasterBuildStepQuery(); + } + + protected function buildCustomSearchFields() { + return array(); + } + + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + + return $query; + } + + protected function getURI($path) { + return '/harbormaster/step/'.$path; + } + + protected function getBuiltinQueryNames() { + return array( + 'all' => pht('All Steps'), + ); + } + + public function buildSavedQueryFromBuiltin($query_key) { + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + + protected function renderResultList( + array $plans, + PhabricatorSavedQuery $query, + array $handles) { + assert_instances_of($plans, 'HarbormasterBuildStep'); + return null; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,6 +7,14 @@ private $phids; private $buildPHIDs; private $buildGenerations; + private $dateCreatedMin; + private $dateCreatedMax; + private $dateStartedMin; + private $dateStartedMax; + private $dateCompletedMin; + private $dateCompletedMax; + private $statuses; + private $needBuildSteps; public function withIDs(array $ids) { @@ -29,6 +37,29 @@ return $this; } + public function withDateCreatedBetween($min, $max) { + $this->dateCreatedMin = $min; + $this->dateCreatedMax = $max; + return $this; + } + + public function withDateStartedBetween($min, $max) { + $this->dateStartedMin = $min; + $this->dateStartedMax = $max; + return $this; + } + + public function withDateCompletedBetween($min, $max) { + $this->dateCompletedMin = $min; + $this->dateCompletedMax = $max; + return $this; + } + + public function withTargetStatuses(array $statuses) { + $this->statuses = $statuses; + return $this; + } + public function needBuildSteps($need_build_steps) { $this->needBuildSteps = $need_build_steps; return $this; @@ -38,10 +69,6 @@ return new HarbormasterBuildTarget(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); @@ -73,6 +100,55 @@ $this->buildGenerations); } + if ($this->dateCreatedMin !== null) { + $where[] = qsprintf( + $conn, + 'dateCreated >= %d', + $this->dateCreatedMin); + } + + if ($this->dateCreatedMax !== null) { + $where[] = qsprintf( + $conn, + 'dateCreated <= %d', + $this->dateCreatedMax); + } + + if ($this->dateStartedMin !== null) { + $where[] = qsprintf( + $conn, + 'dateStarted >= %d', + $this->dateStartedMin); + } + + if ($this->dateStartedMax !== null) { + $where[] = qsprintf( + $conn, + 'dateStarted <= %d', + $this->dateStartedMax); + } + + if ($this->dateCompletedMin !== null) { + $where[] = qsprintf( + $conn, + 'dateCompleted >= %d', + $this->dateCompletedMin); + } + + if ($this->dateCompletedMax !== null) { + $where[] = qsprintf( + $conn, + 'dateCompleted <= %d', + $this->dateCompletedMax); + } + + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn, + 'targetStatus IN (%Ls)', + $this->statuses); + } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildTargetSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -24,6 +24,42 @@ ->setDescription( pht('Search for targets of a given build.')) ->setDatasource(new HarbormasterBuildPlanDatasource()), + id(new PhabricatorSearchDateField()) + ->setLabel(pht('Created After')) + ->setKey('createdStart') + ->setDescription( + pht('Search for targets created on or after a particular date.')), + id(new PhabricatorSearchDateField()) + ->setLabel(pht('Created Before')) + ->setKey('createdEnd') + ->setDescription( + pht('Search for targets created on or before a particular date.')), + id(new PhabricatorSearchDateField()) + ->setLabel(pht('Started After')) + ->setKey('startedStart') + ->setDescription( + pht('Search for targets started on or after a particular date.')), + id(new PhabricatorSearchDateField()) + ->setLabel(pht('Started Before')) + ->setKey('startedEnd') + ->setDescription( + pht('Search for targets started on or before a particular date.')), + id(new PhabricatorSearchDateField()) + ->setLabel(pht('Completed After')) + ->setKey('completedStart') + ->setDescription( + pht('Search for targets completed on or after a particular date.')), + id(new PhabricatorSearchDateField()) + ->setLabel(pht('Completed Before')) + ->setKey('completedEnd') + ->setDescription( + pht('Search for targets completed on or before a particular date.')), + id(new PhabricatorSearchStringListField()) + ->setLabel(pht('Statuses')) + ->setKey('statuses') + ->setAliases(array('status')) + ->setDescription( + pht('Search for targets with given statuses.')), ); } @@ -34,6 +70,28 @@ $query->withBuildPHIDs($map['buildPHIDs']); } + if ($map['createdStart'] !== null || $map['createdEnd'] !== null) { + $query->withDateCreatedBetween( + $map['createdStart'], + $map['createdEnd']); + } + + if ($map['startedStart'] !== null || $map['startedEnd'] !== null) { + $query->withDateStartedBetween( + $map['startedStart'], + $map['startedEnd']); + } + + if ($map['completedStart'] !== null || $map['completedEnd'] !== null) { + $query->withDateCompletedBetween( + $map['completedStart'], + $map['completedEnd']); + } + + if ($map['statuses']) { + $query->withTargetStatuses($map['statuses']); + } + return $query; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildUnitMessageQuery.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildUnitMessageQuery.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/query/HarbormasterBuildUnitMessageQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/query/HarbormasterBuildUnitMessageQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new HarbormasterBuildUnitMessage(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/step/HarbormasterAbortOlderBuildsBuildStepImplementation.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/step/HarbormasterAbortOlderBuildsBuildStepImplementation.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/step/HarbormasterAbortOlderBuildsBuildStepImplementation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/step/HarbormasterAbortOlderBuildsBuildStepImplementation.php 2022-06-14 16:29:55.000000000 +0000 @@ -122,7 +122,7 @@ foreach ($abort_builds as $abort_build) { $abort_build->sendMessage( $viewer, - HarbormasterBuildCommand::COMMAND_ABORT); + HarbormasterBuildMessageAbortTransaction::MESSAGETYPE); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -<?php - -final class HarbormasterPublishFragmentBuildStepImplementation - extends HarbormasterBuildStepImplementation { - - public function getName() { - return pht('Publish Fragment'); - } - - public function getGenericDescription() { - return pht('Publish a fragment based on a file artifact.'); - } - - - public function getBuildStepGroupKey() { - return HarbormasterPrototypeBuildStepGroup::GROUPKEY; - } - - public function getDescription() { - return pht( - 'Publish file artifact %s as fragment %s.', - $this->formatSettingForDescription('artifact'), - $this->formatSettingForDescription('path')); - } - - public function execute( - HarbormasterBuild $build, - HarbormasterBuildTarget $build_target) { - - $settings = $this->getSettings(); - $variables = $build_target->getVariables(); - $viewer = PhabricatorUser::getOmnipotentUser(); - - $path = $this->mergeVariables( - 'vsprintf', - $settings['path'], - $variables); - - $artifact = $build_target->loadArtifact($settings['artifact']); - $impl = $artifact->getArtifactImplementation(); - $file = $impl->loadArtifactFile($viewer); - - $fragment = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->withPaths(array($path)) - ->executeOne(); - - if ($fragment === null) { - PhragmentFragment::createFromFile( - $viewer, - $file, - $path, - PhabricatorPolicies::getMostOpenPolicy(), - PhabricatorPolicies::POLICY_USER); - } else { - if ($file->getMimeType() === 'application/zip') { - $fragment->updateFromZIP($viewer, $file); - } else { - $fragment->updateFromFile($viewer, $file); - } - } - } - - public function getArtifactInputs() { - return array( - array( - 'name' => pht('Publishes File'), - 'key' => $this->getSetting('artifact'), - 'type' => HarbormasterFileArtifact::ARTIFACTCONST, - ), - ); - } - - public function getFieldSpecifications() { - return array( - 'path' => array( - 'name' => pht('Path'), - 'type' => 'text', - 'required' => true, - ), - 'artifact' => array( - 'name' => pht('File Artifact'), - 'type' => 'text', - 'required' => true, - ), - ); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,7 +8,7 @@ } public function getGenericDescription() { - return pht('Upload a file from a host to Phabricator.'); + return pht('Upload a file.'); } public function getBuildStepGroupKey() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuild.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuild.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuild.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuild.php 2022-06-14 16:29:55.000000000 +0000 @@ -18,7 +18,7 @@ private $buildable = self::ATTACHABLE; private $buildPlan = self::ATTACHABLE; private $buildTargets = self::ATTACHABLE; - private $unprocessedCommands = self::ATTACHABLE; + private $unprocessedMessages = self::ATTACHABLE; public static function initializeNewBuild(PhabricatorUser $actor) { return id(new HarbormasterBuild()) @@ -28,7 +28,7 @@ public function delete() { $this->openTransaction(); - $this->deleteUnprocessedCommands(); + $this->deleteUnprocessedMessages(); $result = parent::delete(); $this->saveTransaction(); @@ -128,6 +128,11 @@ 'step.timestamp' => null, 'build.id' => null, 'initiator.phid' => null, + + 'buildable.phid' => null, + 'buildable.object.phid' => null, + 'buildable.container.phid' => null, + 'build.phid' => null, ); foreach ($this->getBuildParameters() as $key => $value) { @@ -145,6 +150,11 @@ $results['build.id'] = $this->getID(); $results['initiator.phid'] = $this->getInitiatorPHID(); + $results['buildable.phid'] = $buildable->getPHID(); + $results['buildable.object.phid'] = $object->getPHID(); + $results['buildable.container.phid'] = $buildable->getContainerPHID(); + $results['build.phid'] = $this->getPHID(); + return $results; } @@ -161,6 +171,16 @@ 'initiator.phid' => pht( 'The PHID of the user or Object that initiated the build, '. 'if applicable.'), + 'buildable.phid' => pht( + 'The object PHID of the Harbormaster Buildable being built.'), + 'buildable.object.phid' => pht( + 'The object PHID of the object (usually a diff or commit) '. + 'being built.'), + 'buildable.container.phid' => pht( + 'The object PHID of the container (usually a revision or repository) '. + 'for the object being built.'), + 'build.phid' => pht( + 'The object PHID of the Harbormaster Build being built.'), ); foreach ($objects as $object) { @@ -187,11 +207,25 @@ return $this->getBuildStatusObject()->isFailed(); } + public function isPending() { + return $this->getBuildstatusObject()->isPending(); + } + public function getURI() { $id = $this->getID(); return "/harbormaster/build/{$id}/"; } + public function getBuildPendingStatusObject() { + list($pending_status) = $this->getUnprocessedMessageState(); + + if ($pending_status !== null) { + return HarbormasterBuildStatus::newBuildStatusObject($pending_status); + } + + return $this->getBuildStatusObject(); + } + protected function getBuildStatusObject() { $status_key = $this->getBuildStatus(); return HarbormasterBuildStatus::newBuildStatusObject($status_key); @@ -202,263 +236,176 @@ } -/* -( Build Commands )----------------------------------------------------- */ - - - private function getUnprocessedCommands() { - return $this->assertAttached($this->unprocessedCommands); - } - - public function attachUnprocessedCommands(array $commands) { - $this->unprocessedCommands = $commands; - return $this; - } - - public function canRestartBuild() { - try { - $this->assertCanRestartBuild(); - return true; - } catch (HarbormasterRestartException $ex) { - return false; - } - } - - public function assertCanRestartBuild() { - if ($this->isAutobuild()) { - throw new HarbormasterRestartException( - pht('Can Not Restart Autobuild'), - pht( - 'This build can not be restarted because it is an automatic '. - 'build.')); - } - - $restartable = HarbormasterBuildPlanBehavior::BEHAVIOR_RESTARTABLE; - $plan = $this->getBuildPlan(); - - // See T13526. Users who can't see the "BuildPlan" can end up here with - // no object. This is highly questionable. - if (!$plan) { - throw new HarbormasterRestartException( - pht('No Build Plan Permission'), - pht( - 'You can not restart this build because you do not have '. - 'permission to access the build plan.')); - } - - $option = HarbormasterBuildPlanBehavior::getBehavior($restartable) - ->getPlanOption($plan); - $option_key = $option->getKey(); - - $never_restartable = HarbormasterBuildPlanBehavior::RESTARTABLE_NEVER; - $is_never = ($option_key === $never_restartable); - if ($is_never) { - throw new HarbormasterRestartException( - pht('Build Plan Prevents Restart'), - pht( - 'This build can not be restarted because the build plan is '. - 'configured to prevent the build from restarting.')); - } +/* -( Build Messages )----------------------------------------------------- */ - $failed_restartable = HarbormasterBuildPlanBehavior::RESTARTABLE_IF_FAILED; - $is_failed = ($option_key === $failed_restartable); - if ($is_failed) { - if (!$this->isFailed()) { - throw new HarbormasterRestartException( - pht('Only Restartable if Failed'), - pht( - 'This build can not be restarted because the build plan is '. - 'configured to prevent the build from restarting unless it '. - 'has failed, and it has not failed.')); - } - } - if ($this->isRestarting()) { - throw new HarbormasterRestartException( - pht('Already Restarting'), - pht( - 'This build is already restarting. You can not reissue a restart '. - 'command to a restarting build.')); - } + private function getUnprocessedMessages() { + return $this->assertAttached($this->unprocessedMessages); } - public function canPauseBuild() { - if ($this->isAutobuild()) { - return false; - } + public function getUnprocessedMessagesForApply() { + $unprocessed_state = $this->getUnprocessedMessageState(); + list($pending_status, $apply_messages) = $unprocessed_state; - return !$this->isComplete() && - !$this->isPaused() && - !$this->isPausing(); + return $apply_messages; } - public function canAbortBuild() { - if ($this->isAutobuild()) { - return false; - } - - return !$this->isComplete(); - } + private function getUnprocessedMessageState() { + // NOTE: If a build has multiple unprocessed messages, we'll ignore + // messages that are obsoleted by a later or stronger message. + // + // For example, if a build has both "pause" and "abort" messages in queue, + // we just ignore the "pause" message and perform an "abort", since pausing + // first wouldn't affect the final state, so we can just skip it. + // + // Likewise, if a build has both "restart" and "abort" messages, the most + // recent message is controlling: we'll take whichever action a command + // was most recently issued for. - public function canResumeBuild() { - if ($this->isAutobuild()) { - return false; - } + $is_restarting = false; + $is_aborting = false; + $is_pausing = false; + $is_resuming = false; - return $this->isPaused() && - !$this->isResuming(); - } + $apply_messages = array(); - public function isPausing() { - $is_pausing = false; - foreach ($this->getUnprocessedCommands() as $command_object) { - $command = $command_object->getCommand(); - switch ($command) { - case HarbormasterBuildCommand::COMMAND_PAUSE: - $is_pausing = true; + foreach ($this->getUnprocessedMessages() as $message_object) { + $message_type = $message_object->getType(); + switch ($message_type) { + case HarbormasterBuildMessageRestartTransaction::MESSAGETYPE: + $is_restarting = true; + $is_aborting = false; + $apply_messages = array($message_object); break; - case HarbormasterBuildCommand::COMMAND_RESUME: - case HarbormasterBuildCommand::COMMAND_RESTART: - $is_pausing = false; + case HarbormasterBuildMessageAbortTransaction::MESSAGETYPE: + $is_aborting = true; + $is_restarting = false; + $apply_messages = array($message_object); break; - case HarbormasterBuildCommand::COMMAND_ABORT: + case HarbormasterBuildMessagePauseTransaction::MESSAGETYPE: $is_pausing = true; + $is_resuming = false; + $apply_messages = array($message_object); + break; + case HarbormasterBuildMessageResumeTransaction::MESSAGETYPE: + $is_resuming = true; + $is_pausing = false; + $apply_messages = array($message_object); break; } } - return $is_pausing; + $pending_status = null; + if ($is_restarting) { + $pending_status = HarbormasterBuildStatus::PENDING_RESTARTING; + } else if ($is_aborting) { + $pending_status = HarbormasterBuildStatus::PENDING_ABORTING; + } else if ($is_pausing) { + $pending_status = HarbormasterBuildStatus::PENDING_PAUSING; + } else if ($is_resuming) { + $pending_status = HarbormasterBuildStatus::PENDING_RESUMING; + } + + return array($pending_status, $apply_messages); + } + + public function attachUnprocessedMessages(array $messages) { + assert_instances_of($messages, 'HarbormasterBuildMessage'); + $this->unprocessedMessages = $messages; + return $this; } - public function isResuming() { - $is_resuming = false; - foreach ($this->getUnprocessedCommands() as $command_object) { - $command = $command_object->getCommand(); - switch ($command) { - case HarbormasterBuildCommand::COMMAND_RESTART: - case HarbormasterBuildCommand::COMMAND_RESUME: - $is_resuming = true; - break; - case HarbormasterBuildCommand::COMMAND_PAUSE: - $is_resuming = false; - break; - case HarbormasterBuildCommand::COMMAND_ABORT: - $is_resuming = false; - break; - } - } + public function isPausing() { + return $this->getBuildPendingStatusObject()->isPausing(); + } - return $is_resuming; + public function isResuming() { + return $this->getBuildPendingStatusObject()->isResuming(); } public function isRestarting() { - $is_restarting = false; - foreach ($this->getUnprocessedCommands() as $command_object) { - $command = $command_object->getCommand(); - switch ($command) { - case HarbormasterBuildCommand::COMMAND_RESTART: - $is_restarting = true; - break; - } - } - - return $is_restarting; + return $this->getBuildPendingStatusObject()->isRestarting(); } public function isAborting() { - $is_aborting = false; - foreach ($this->getUnprocessedCommands() as $command_object) { - $command = $command_object->getCommand(); - switch ($command) { - case HarbormasterBuildCommand::COMMAND_ABORT: - $is_aborting = true; - break; - } + return $this->getBuildPendingStatusObject()->isAborting(); + } + + public function markUnprocessedMessagesAsProcessed() { + foreach ($this->getUnprocessedMessages() as $key => $message_object) { + $message_object + ->setIsConsumed(1) + ->save(); } - return $is_aborting; + return $this; } - public function deleteUnprocessedCommands() { - foreach ($this->getUnprocessedCommands() as $key => $command_object) { - $command_object->delete(); - unset($this->unprocessedCommands[$key]); + public function deleteUnprocessedMessages() { + foreach ($this->getUnprocessedMessages() as $key => $message_object) { + $message_object->delete(); + unset($this->unprocessedMessages[$key]); } return $this; } - public function canIssueCommand(PhabricatorUser $viewer, $command) { - try { - $this->assertCanIssueCommand($viewer, $command); - return true; - } catch (Exception $ex) { - return false; - } + public function sendMessage(PhabricatorUser $viewer, $message_type) { + HarbormasterBuildMessage::initializeNewMessage($viewer) + ->setReceiverPHID($this->getPHID()) + ->setType($message_type) + ->save(); + + PhabricatorWorker::scheduleTask( + 'HarbormasterBuildWorker', + array( + 'buildID' => $this->getID(), + ), + array( + 'objectPHID' => $this->getPHID(), + 'containerPHID' => $this->getBuildablePHID(), + )); } - public function assertCanIssueCommand(PhabricatorUser $viewer, $command) { - $plan = $this->getBuildPlan(); + public function releaseAllArtifacts(PhabricatorUser $viewer) { + $targets = id(new HarbormasterBuildTargetQuery()) + ->setViewer($viewer) + ->withBuildPHIDs(array($this->getPHID())) + ->withBuildGenerations(array($this->getBuildGeneration())) + ->execute(); - // See T13526. Users without permission to access the build plan can - // currently end up here with no "BuildPlan" object. - if (!$plan) { - return false; + if (!$targets) { + return; } - $need_edit = true; - switch ($command) { - case HarbormasterBuildCommand::COMMAND_RESTART: - case HarbormasterBuildCommand::COMMAND_PAUSE: - case HarbormasterBuildCommand::COMMAND_RESUME: - case HarbormasterBuildCommand::COMMAND_ABORT: - if ($plan->canRunWithoutEditCapability()) { - $need_edit = false; - } - break; - default: - throw new Exception( - pht( - 'Invalid Harbormaster build command "%s".', - $command)); - } + $target_phids = mpull($targets, 'getPHID'); - // Issuing these commands requires that you be able to edit the build, to - // prevent enemy engineers from sabotaging your builds. See T9614. - if ($need_edit) { - PhabricatorPolicyFilter::requireCapability( - $viewer, - $plan, - PhabricatorPolicyCapability::CAN_EDIT); + $artifacts = id(new HarbormasterBuildArtifactQuery()) + ->setViewer($viewer) + ->withBuildTargetPHIDs($target_phids) + ->withIsReleased(false) + ->execute(); + foreach ($artifacts as $artifact) { + $artifact->releaseArtifact(); } } - public function sendMessage(PhabricatorUser $viewer, $command) { - // TODO: This should not be an editor transaction, but there are plans to - // merge BuildCommand into BuildMessage which should moot this. As this - // exists today, it can race against BuildEngine. - - // This is a bogus content source, but this whole flow should be obsolete - // soon. - $content_source = PhabricatorContentSource::newForSource( - PhabricatorConsoleContentSource::SOURCECONST); - - $editor = id(new HarbormasterBuildTransactionEditor()) - ->setActor($viewer) - ->setContentSource($content_source) - ->setContinueOnNoEffect(true) - ->setContinueOnMissingFields(true); - - $viewer_phid = $viewer->getPHID(); - if (!$viewer_phid) { - $acting_phid = id(new PhabricatorHarbormasterApplication())->getPHID(); - $editor->setActingAsPHID($acting_phid); - } + public function restartBuild(PhabricatorUser $viewer) { + // TODO: This should become transactional. + + // We're restarting the build, so release all previous artifacts. + $this->releaseAllArtifacts($viewer); + + // Increment the build generation counter on the build. + $this->setBuildGeneration($this->getBuildGeneration() + 1); - $xaction = id(new HarbormasterBuildTransaction()) - ->setTransactionType(HarbormasterBuildTransaction::TYPE_COMMAND) - ->setNewValue($command); + // Currently running targets should periodically check their build + // generation (which won't have changed) against the build's generation. + // If it is different, they will automatically stop what they're doing + // and abort. - $editor->applyTransactions($this, array($xaction)); + // Previously we used to delete targets, logs and artifacts here. Instead, + // leave them around so users can view previous generations of this build. } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php 2022-06-14 16:29:55.000000000 +0000 @@ -119,6 +119,15 @@ 'key_build' => array( 'columns' => array('buildPHID', 'buildStepPHID'), ), + 'key_started' => array( + 'columns' => array('dateStarted'), + ), + 'key_completed' => array( + 'columns' => array('dateCompleted'), + ), + 'key_created' => array( + 'columns' => array('dateCreated'), + ), ), ) + parent::getConfiguration(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,7 +4,8 @@ implements PhabricatorApplicationTransactionInterface, PhabricatorPolicyInterface, - PhabricatorCustomFieldInterface { + PhabricatorCustomFieldInterface, + PhabricatorConduitResultInterface { protected $name; protected $description; @@ -169,5 +170,45 @@ return $this; } +/* -( PhabricatorConduitResultInterface )---------------------------------- */ + + + public function getFieldSpecificationsForConduit() { + return array( + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('name') + ->setType('string') + ->setDescription(pht('The name of the build step.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('description') + ->setType('remarkup') + ->setDescription(pht('The build step description.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('buildPlanPHID') + ->setType('phid') + ->setDescription( + pht( + 'The PHID of the build plan this build step belongs to.')), + ); + } + + public function getFieldValuesForConduit() { + // T6203: This can be removed once the field becomes non-nullable. + $name = $this->getName(); + $name = phutil_string_cast($name); + + return array( + 'name' => $name, + 'description' => array( + 'raw' => $this->getDescription(), + ), + 'buildPlanPHID' => $this->getBuildPlanPHID(), + ); + } + + public function getConduitSearchAttachments() { + return array(); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,10 +1,7 @@ <?php final class HarbormasterBuildableTransaction - extends PhabricatorApplicationTransaction { - - const TYPE_CREATE = 'harbormaster:buildable:create'; - const TYPE_COMMAND = 'harbormaster:buildable:command'; + extends PhabricatorModularTransaction { public function getApplicationName() { return 'harbormaster'; @@ -14,74 +11,8 @@ return HarbormasterBuildablePHIDType::TYPECONST; } - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CREATE: - return pht( - '%s created this buildable.', - $this->renderHandleLink($author_phid)); - case self::TYPE_COMMAND: - switch ($new) { - case HarbormasterBuildCommand::COMMAND_RESTART: - return pht( - '%s restarted this buildable.', - $this->renderHandleLink($author_phid)); - case HarbormasterBuildCommand::COMMAND_RESUME: - return pht( - '%s resumed this buildable.', - $this->renderHandleLink($author_phid)); - case HarbormasterBuildCommand::COMMAND_PAUSE: - return pht( - '%s paused this buildable.', - $this->renderHandleLink($author_phid)); - } - } - return parent::getTitle(); + public function getBaseTransactionClass() { + return 'HarbormasterBuildableTransactionType'; } - public function getIcon() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CREATE: - return 'fa-plus'; - case self::TYPE_COMMAND: - switch ($new) { - case HarbormasterBuildCommand::COMMAND_RESTART: - return 'fa-backward'; - case HarbormasterBuildCommand::COMMAND_RESUME: - return 'fa-play'; - case HarbormasterBuildCommand::COMMAND_PAUSE: - return 'fa-pause'; - } - } - - return parent::getIcon(); - } - - public function getColor() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CREATE: - return 'green'; - case self::TYPE_COMMAND: - switch ($new) { - case HarbormasterBuildCommand::COMMAND_PAUSE: - return 'red'; - } - } - return parent::getColor(); - } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/HarbormasterBuildCommand.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/HarbormasterBuildCommand.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/HarbormasterBuildCommand.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/HarbormasterBuildCommand.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -<?php - -final class HarbormasterBuildCommand extends HarbormasterDAO { - - const COMMAND_PAUSE = 'pause'; - const COMMAND_RESUME = 'resume'; - const COMMAND_RESTART = 'restart'; - const COMMAND_ABORT = 'abort'; - - protected $authorPHID; - protected $targetPHID; - protected $command; - - protected function getConfiguration() { - return array( - self::CONFIG_COLUMN_SCHEMA => array( - 'command' => 'text128', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_target' => array( - 'columns' => array('targetPHID'), - ), - ), - ) + parent::getConfiguration(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,10 +1,7 @@ <?php final class HarbormasterBuildTransaction - extends PhabricatorApplicationTransaction { - - const TYPE_CREATE = 'harbormaster:build:create'; - const TYPE_COMMAND = 'harbormaster:build:command'; + extends PhabricatorModularTransaction { public function getApplicationName() { return 'harbormaster'; @@ -14,81 +11,8 @@ return HarbormasterBuildPHIDType::TYPECONST; } - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CREATE: - return pht( - '%s created this build.', - $this->renderHandleLink($author_phid)); - case self::TYPE_COMMAND: - switch ($new) { - case HarbormasterBuildCommand::COMMAND_RESTART: - return pht( - '%s restarted this build.', - $this->renderHandleLink($author_phid)); - case HarbormasterBuildCommand::COMMAND_ABORT: - return pht( - '%s aborted this build.', - $this->renderHandleLink($author_phid)); - case HarbormasterBuildCommand::COMMAND_RESUME: - return pht( - '%s resumed this build.', - $this->renderHandleLink($author_phid)); - case HarbormasterBuildCommand::COMMAND_PAUSE: - return pht( - '%s paused this build.', - $this->renderHandleLink($author_phid)); - } - } - return parent::getTitle(); + public function getBaseTransactionClass() { + return 'HarbormasterBuildTransactionType'; } - public function getIcon() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CREATE: - return 'fa-plus'; - case self::TYPE_COMMAND: - switch ($new) { - case HarbormasterBuildCommand::COMMAND_RESTART: - return 'fa-backward'; - case HarbormasterBuildCommand::COMMAND_RESUME: - return 'fa-play'; - case HarbormasterBuildCommand::COMMAND_PAUSE: - return 'fa-pause'; - case HarbormasterBuildCommand::COMMAND_ABORT: - return 'fa-exclamation-triangle'; - } - } - - return parent::getIcon(); - } - - public function getColor() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CREATE: - return 'green'; - case self::TYPE_COMMAND: - switch ($new) { - case HarbormasterBuildCommand::COMMAND_PAUSE: - case HarbormasterBuildCommand::COMMAND_ABORT: - return 'red'; - } - } - return parent::getColor(); - } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/view/HarbormasterUnitSummaryView.php 2022-06-14 16:29:55.000000000 +0000 @@ -5,7 +5,6 @@ private $buildable; private $messages; private $limit; - private $excuse; private $showViewAll; public function setBuildable(HarbormasterBuildable $buildable) { @@ -23,11 +22,6 @@ return $this; } - public function setExcuse($excuse) { - $this->excuse = $excuse; - return $this; - } - public function setShowViewAll($show_view_all) { $this->showViewAll = $show_view_all; return $this; @@ -88,21 +82,6 @@ $table->setLimit($this->limit); } - $excuse = $this->excuse; - if (strlen($excuse)) { - $excuse_icon = id(new PHUIIconView()) - ->setIcon('fa-commenting-o red'); - - $table->setNotice( - array( - $excuse_icon, - ' ', - phutil_tag('strong', array(), pht('Excuse:')), - ' ', - $excuse, - )); - } - $box->setTable($table); return $box; diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageAbortTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageAbortTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageAbortTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageAbortTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,117 @@ +<?php + +final class HarbormasterBuildMessageAbortTransaction + extends HarbormasterBuildMessageTransaction { + + const TRANSACTIONTYPE = 'message/abort'; + const MESSAGETYPE = 'abort'; + + public function getHarbormasterBuildMessageName() { + return pht('Abort Build'); + } + + public function getHarbormasterBuildableMessageName() { + return pht('Abort Builds'); + } + + public function newConfirmPromptTitle() { + return pht('Really abort build?'); + } + + public function getHarbormasterBuildableMessageEffect() { + return pht('Build will abort.'); + } + + public function newConfirmPromptBody() { + return pht( + 'Progress on this build will be discarded. Really abort build?'); + } + + public function getHarbormasterBuildMessageDescription() { + return pht('Abort the build, discarding progress.'); + } + + public function newBuildableConfirmPromptTitle( + array $builds, + array $sendable) { + return pht( + 'Really abort %s build(s)?', + phutil_count($builds)); + } + + public function newBuildableConfirmPromptBody( + array $builds, + array $sendable) { + + if (count($sendable) === count($builds)) { + return pht( + 'If you abort all builds, work will halt immediately. Work '. + 'will be discarded, and builds must be completely restarted.'); + } else { + return pht( + 'You can only abort some builds. Work will halt immediately on '. + 'builds you can abort. Progress will be discarded, and builds must '. + 'be completely restarted if you want them to complete.'); + } + } + + public function getTitle() { + return pht( + '%s aborted this build.', + $this->renderAuthor()); + } + + public function getIcon() { + return 'fa-exclamation-triangle'; + } + + public function getColor() { + return 'red'; + } + + public function applyInternalEffects($object, $value) { + $actor = $this->getActor(); + $build = $object; + + $build->setBuildStatus(HarbormasterBuildStatus::STATUS_ABORTED); + } + + public function applyExternalEffects($object, $value) { + $actor = $this->getActor(); + $build = $object; + + $build->releaseAllArtifacts($actor); + } + + protected function newCanApplyMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isAutobuild()) { + throw new HarbormasterMessageException( + pht('Unable to Abort Build'), + pht( + 'You can not abort a build that uses an autoplan.')); + } + + if ($build->isComplete()) { + throw new HarbormasterMessageException( + pht('Unable to Abort Build'), + pht( + 'You can not abort this biuld because it is already complete.')); + } + } + + protected function newCanSendMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isAborting()) { + throw new HarbormasterMessageException( + pht('Unable to Abort Build'), + pht( + 'You can not abort this build because it is already aborting.')); + } + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessagePauseTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessagePauseTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessagePauseTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessagePauseTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,126 @@ +<?php + +final class HarbormasterBuildMessagePauseTransaction + extends HarbormasterBuildMessageTransaction { + + const TRANSACTIONTYPE = 'message/pause'; + const MESSAGETYPE = 'pause'; + + public function getHarbormasterBuildMessageName() { + return pht('Pause Build'); + } + + public function getHarbormasterBuildableMessageName() { + return pht('Pause Builds'); + } + + public function newConfirmPromptTitle() { + return pht('Really pause build?'); + } + + public function getHarbormasterBuildableMessageEffect() { + return pht('Build will pause.'); + } + + public function newConfirmPromptBody() { + return pht( + 'If you pause this build, work will halt once the current steps '. + 'complete. You can resume the build later.'); + } + + + public function getHarbormasterBuildMessageDescription() { + return pht('Pause the build.'); + } + + public function newBuildableConfirmPromptTitle( + array $builds, + array $sendable) { + return pht( + 'Really pause %s build(s)?', + phutil_count($builds)); + } + + public function newBuildableConfirmPromptBody( + array $builds, + array $sendable) { + + if (count($sendable) === count($builds)) { + return pht( + 'If you pause all builds, work will halt once the current steps '. + 'complete. You can resume the builds later.'); + } else { + return pht( + 'You can only pause some builds. Once the current steps complete, '. + 'work will halt on builds you can pause. You can resume the builds '. + 'later.'); + } + } + + public function getTitle() { + return pht( + '%s paused this build.', + $this->renderAuthor()); + } + + public function getIcon() { + return 'fa-pause'; + } + + public function getColor() { + return 'red'; + } + + public function applyInternalEffects($object, $value) { + $actor = $this->getActor(); + $build = $object; + + $build->setBuildStatus(HarbormasterBuildStatus::STATUS_PAUSED); + } + + protected function newCanApplyMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isAutobuild()) { + throw new HarbormasterMessageException( + pht('Unable to Pause Build'), + pht('You can not pause a build that uses an autoplan.')); + } + + if ($build->isPaused()) { + throw new HarbormasterMessageException( + pht('Unable to Pause Build'), + pht('You can not pause this build because it is already paused.')); + } + + if ($build->isComplete()) { + throw new HarbormasterMessageException( + pht('Unable to Pause Build'), + pht('You can not pause this build because it has already completed.')); + } + } + + protected function newCanSendMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isPausing()) { + throw new HarbormasterMessageException( + pht('Unable to Pause Build'), + pht('You can not pause this build because it is already pausing.')); + } + + if ($build->isRestarting()) { + throw new HarbormasterMessageException( + pht('Unable to Pause Build'), + pht('You can not pause this build because it is already restarting.')); + } + + if ($build->isAborting()) { + throw new HarbormasterMessageException( + pht('Unable to Pause Build'), + pht('You can not pause this build because it is already aborting.')); + } + } +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageRestartTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageRestartTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageRestartTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageRestartTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,171 @@ +<?php + +final class HarbormasterBuildMessageRestartTransaction + extends HarbormasterBuildMessageTransaction { + + const TRANSACTIONTYPE = 'message/restart'; + const MESSAGETYPE = 'restart'; + + public function getHarbormasterBuildMessageName() { + return pht('Restart Build'); + } + + public function getHarbormasterBuildableMessageName() { + return pht('Restart Builds'); + } + + public function getHarbormasterBuildableMessageEffect() { + return pht('Build will restart.'); + } + + public function newConfirmPromptTitle() { + return pht('Really restart build?'); + } + + public function newConfirmPromptBody() { + return pht( + 'Progress on this build will be discarded and the build will restart. '. + 'Side effects of the build will occur again. Really restart build?'); + } + + + public function getHarbormasterBuildMessageDescription() { + return pht('Restart the build, discarding all progress.'); + } + + public function newBuildableConfirmPromptTitle( + array $builds, + array $sendable) { + return pht( + 'Really restart %s build(s)?', + phutil_count($builds)); + } + + public function newBuildableConfirmPromptBody( + array $builds, + array $sendable) { + + if (count($sendable) === count($builds)) { + return pht( + 'All builds will restart.'); + } else { + return pht( + 'You can only restart some builds.'); + } + } + + public function newBuildableConfirmPromptWarnings( + array $builds, + array $sendable) { + + $building = false; + foreach ($sendable as $build) { + if ($build->isBuilding()) { + $building = true; + break; + } + } + + $warnings = array(); + + if ($building) { + $warnings[] = pht( + 'Progress on running builds will be discarded.'); + } + + if ($sendable) { + $warnings[] = pht( + 'When a build is restarted, side effects associated with '. + 'the build may occur again.'); + } + + return $warnings; + } + + public function getTitle() { + return pht( + '%s restarted this build.', + $this->renderAuthor()); + } + + public function getIcon() { + return 'fa-repeat'; + } + + public function applyInternalEffects($object, $value) { + $actor = $this->getActor(); + $build = $object; + + $build->restartBuild($actor); + $build->setBuildStatus(HarbormasterBuildStatus::STATUS_BUILDING); + } + + protected function newCanApplyMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isAutobuild()) { + throw new HarbormasterMessageException( + pht('Can Not Restart Autobuild'), + pht( + 'This build can not be restarted because it is an automatic '. + 'build.')); + } + + $restartable = HarbormasterBuildPlanBehavior::BEHAVIOR_RESTARTABLE; + $plan = $build->getBuildPlan(); + + // See T13526. Users who can't see the "BuildPlan" can end up here with + // no object. This is highly questionable. + if (!$plan) { + throw new HarbormasterMessageException( + pht('No Build Plan Permission'), + pht( + 'You can not restart this build because you do not have '. + 'permission to access the build plan.')); + } + + $option = HarbormasterBuildPlanBehavior::getBehavior($restartable) + ->getPlanOption($plan); + $option_key = $option->getKey(); + + $never_restartable = HarbormasterBuildPlanBehavior::RESTARTABLE_NEVER; + $is_never = ($option_key === $never_restartable); + if ($is_never) { + throw new HarbormasterMessageException( + pht('Build Plan Prevents Restart'), + pht( + 'This build can not be restarted because the build plan is '. + 'configured to prevent the build from restarting.')); + } + + $failed_restartable = HarbormasterBuildPlanBehavior::RESTARTABLE_IF_FAILED; + $is_failed = ($option_key === $failed_restartable); + if ($is_failed) { + if (!$this->isFailed()) { + throw new HarbormasterMessageException( + pht('Only Restartable if Failed'), + pht( + 'This build can not be restarted because the build plan is '. + 'configured to prevent the build from restarting unless it '. + 'has failed, and it has not failed.')); + } + } + + } + + protected function newCanSendMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isRestarting()) { + throw new HarbormasterMessageException( + pht('Already Restarting'), + pht( + 'This build is already restarting. You can not reissue a restart '. + 'command to a restarting build.')); + } + + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,119 @@ +<?php + +final class HarbormasterBuildMessageResumeTransaction + extends HarbormasterBuildMessageTransaction { + + const TRANSACTIONTYPE = 'message/resume'; + const MESSAGETYPE = 'resume'; + + public function getHarbormasterBuildMessageName() { + return pht('Resume Build'); + } + + public function getHarbormasterBuildableMessageName() { + return pht('Resume Builds'); + } + + public function getHarbormasterBuildableMessageEffect() { + return pht('Build will resume.'); + } + + public function newConfirmPromptTitle() { + return pht('Really resume build?'); + } + + public function newConfirmPromptBody() { + return pht( + 'Work will continue on the build. Really resume?'); + } + + public function getHarbormasterBuildMessageDescription() { + return pht('Resume work on a previously paused build.'); + } + + public function newBuildableConfirmPromptTitle( + array $builds, + array $sendable) { + return pht( + 'Really resume %s build(s)?', + phutil_count($builds)); + } + + public function newBuildableConfirmPromptBody( + array $builds, + array $sendable) { + + if (count($sendable) === count($builds)) { + return pht( + 'Work will continue on all builds. Really resume?'); + } else { + return pht( + 'You can only resume some builds. Work will continue on builds '. + 'you have permission to resume.'); + } + } + + public function getTitle() { + return pht( + '%s resumed this build.', + $this->renderAuthor()); + } + + public function getIcon() { + return 'fa-play'; + } + + public function applyInternalEffects($object, $value) { + $actor = $this->getActor(); + $build = $object; + + $build->setBuildStatus(HarbormasterBuildStatus::STATUS_BUILDING); + } + + protected function newCanApplyMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isAutobuild()) { + throw new HarbormasterMessageException( + pht('Unable to Resume Build'), + pht( + 'You can not resume a build that uses an autoplan.')); + } + + if (!$build->isPaused() && !$build->isPausing()) { + throw new HarbormasterMessageException( + pht('Unable to Resume Build'), + pht( + 'You can not resume this build because it is not paused. You can '. + 'only resume a paused build.')); + } + + } + + protected function newCanSendMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + if ($build->isResuming()) { + throw new HarbormasterMessageException( + pht('Unable to Resume Build'), + pht( + 'You can not resume this build beacuse it is already resuming.')); + } + + if ($build->isRestarting()) { + throw new HarbormasterMessageException( + pht('Unable to Resume Build'), + pht('You can not resume this build because it is already restarting.')); + } + + if ($build->isAborting()) { + throw new HarbormasterMessageException( + pht('Unable to Resume Build'), + pht('You can not resume this build because it is already aborting.')); + } + + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildMessageTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,158 @@ +<?php + +abstract class HarbormasterBuildMessageTransaction + extends HarbormasterBuildTransactionType { + + final public function getHarbormasterBuildMessageType() { + return $this->getPhobjectClassConstant('MESSAGETYPE'); + } + + abstract public function getHarbormasterBuildMessageName(); + abstract public function getHarbormasterBuildMessageDescription(); + abstract public function getHarbormasterBuildableMessageName(); + abstract public function getHarbormasterBuildableMessageEffect(); + + abstract public function newConfirmPromptTitle(); + abstract public function newConfirmPromptBody(); + + abstract public function newBuildableConfirmPromptTitle( + array $builds, + array $sendable); + + abstract public function newBuildableConfirmPromptBody( + array $builds, + array $sendable); + + public function newBuildableConfirmPromptWarnings( + array $builds, + array $sendable) { + return array(); + } + + final public function generateOldValue($object) { + return null; + } + + final public function getTransactionTypeForConduit($xaction) { + return 'message'; + } + + final public function getFieldValuesForConduit($xaction, $data) { + return array( + 'type' => $xaction->getNewValue(), + ); + } + + final public static function getAllMessages() { + $message_xactions = id(new PhutilClassMapQuery()) + ->setAncestorClass(__CLASS__) + ->execute(); + + return $message_xactions; + } + + final public static function getTransactionObjectForMessageType( + $message_type) { + $message_xactions = self::getAllMessages(); + + foreach ($message_xactions as $message_xaction) { + $xaction_type = $message_xaction->getHarbormasterBuildMessageType(); + if ($xaction_type === $message_type) { + return $message_xaction; + } + } + + return null; + } + + final public static function getTransactionTypeForMessageType($message_type) { + $message_xaction = self::getTransactionObjectForMessageType($message_type); + + if ($message_xaction) { + return $message_xaction->getTransactionTypeConstant(); + } + + return null; + } + + final public function getTransactionHasEffect($object, $old, $new) { + return $this->canApplyMessage($this->getActor(), $object); + } + + final public function canApplyMessage( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + try { + $this->assertCanApplyMessage($viewer, $build); + return true; + } catch (HarbormasterMessageException $ex) { + return false; + } + } + + final public function canSendMessage( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + + try { + $this->assertCanSendMessage($viewer, $build); + return true; + } catch (HarbormasterMessageException $ex) { + return false; + } + } + + final public function assertCanApplyMessage( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + $this->newCanApplyMessageAssertion($viewer, $build); + } + + final public function assertCanSendMessage( + PhabricatorUser $viewer, + HarbormasterBuild $build) { + $plan = $build->getBuildPlan(); + + // See T13526. Users without permission to access the build plan can + // currently end up here with no "BuildPlan" object. + if (!$plan) { + throw new HarbormasterMessageException( + pht('No Build Plan Permission'), + pht( + 'You can not issue this command because you do not have '. + 'permission to access the build plan for this build.')); + } + + // Issuing these commands requires that you be able to edit the build, to + // prevent enemy engineers from sabotaging your builds. See T9614. + if (!$plan->canRunWithoutEditCapability()) { + try { + PhabricatorPolicyFilter::requireCapability( + $viewer, + $plan, + PhabricatorPolicyCapability::CAN_EDIT); + } catch (PhabricatorPolicyException $ex) { + throw new HarbormasterMessageException( + pht('Insufficent Build Plan Permission'), + pht( + 'The build plan for this build is configured to prevent '. + 'users who can not edit it from issuing commands to the '. + 'build, and you do not have permission to edit the build '. + 'plan.')); + } + } + + $this->newCanSendMessageAssertion($viewer, $build); + $this->assertCanApplyMessage($viewer, $build); + } + + abstract protected function newCanSendMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build); + + abstract protected function newCanApplyMessageAssertion( + PhabricatorUser $viewer, + HarbormasterBuild $build); + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildTransactionType.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildTransactionType.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildTransactionType.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/build/HarbormasterBuildTransactionType.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,4 @@ +<?php + +abstract class HarbormasterBuildTransactionType + extends PhabricatorModularTransactionType {} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableMessageTransaction.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableMessageTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableMessageTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableMessageTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,65 @@ +<?php + +final class HarbormasterBuildableMessageTransaction + extends HarbormasterBuildableTransactionType { + + const TRANSACTIONTYPE = 'harbormaster:buildable:command'; + + public function generateOldValue($object) { + return null; + } + + public function getTitle() { + $new = $this->getNewValue(); + + switch ($new) { + case HarbormasterBuildMessageRestartTransaction::MESSAGETYPE: + return pht( + '%s restarted this buildable.', + $this->renderAuthor()); + case HarbormasterBuildMessageResumeTransaction::MESSAGETYPE: + return pht( + '%s resumed this buildable.', + $this->renderAuthor()); + case HarbormasterBuildMessagePauseTransaction::MESSAGETYPE: + return pht( + '%s paused this buildable.', + $this->renderAuthor()); + case HarbormasterBuildMessageAbortTransaction::MESSAGETYPE: + return pht( + '%s aborted this buildable.', + $this->renderAuthor()); + } + + return parent::getTitle(); + } + + public function getIcon() { + $new = $this->getNewValue(); + + switch ($new) { + case HarbormasterBuildMessageRestartTransaction::MESSAGETYPE: + return 'fa-backward'; + case HarbormasterBuildMessageResumeTransaction::MESSAGETYPE: + return 'fa-play'; + case HarbormasterBuildMessagePauseTransaction::MESSAGETYPE: + return 'fa-pause'; + case HarbormasterBuildMessageAbortTransaction::MESSAGETYPE: + return 'fa-exclamation-triangle'; + } + + return parent::getIcon(); + } + + public function getColor() { + $new = $this->getNewValue(); + + switch ($new) { + case HarbormasterBuildMessagePauseTransaction::MESSAGETYPE: + return 'red'; + } + + return parent::getColor(); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableTransactionType.php phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableTransactionType.php --- phabricator-0~git20200925/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableTransactionType.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/harbormaster/xaction/buildable/HarbormasterBuildableTransactionType.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,4 @@ +<?php + +abstract class HarbormasterBuildableTransactionType + extends PhabricatorModularTransactionType {} diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/adapter/HeraldAdapter.php phabricator-0~git20220903/phabricator/src/applications/herald/adapter/HeraldAdapter.php --- phabricator-0~git20200925/phabricator/src/applications/herald/adapter/HeraldAdapter.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/adapter/HeraldAdapter.php 2022-06-14 16:29:55.000000000 +0000 @@ -520,21 +520,29 @@ case self::CONDITION_NOT_REGEXP: $result_if_match = ($condition_type == self::CONDITION_REGEXP); + // We add the 'S' flag because we use the regexp multiple times. + // It shouldn't cause any troubles if the flag is already there + // - /.*/S is evaluated same as /.*/SS. + $condition_pattern = $condition_value.'S'; + foreach ((array)$field_value as $value) { - // We add the 'S' flag because we use the regexp multiple times. - // It shouldn't cause any troubles if the flag is already there - // - /.*/S is evaluated same as /.*/SS. - $result = @preg_match($condition_value.'S', $value); - if ($result === false) { - throw new HeraldInvalidConditionException( - pht( - 'Regular expression "%s" in Herald rule "%s" is not valid, '. - 'or exceeded backtracking or recursion limits while '. - 'executing. Verify the expression and correct it or rewrite '. - 'it with less backtracking.', - $condition_value, - $rule->getMonogram())); + try { + $result = phutil_preg_match($condition_pattern, $value); + } catch (PhutilRegexException $ex) { + $message = array(); + $message[] = pht( + 'Regular expression "%s" in Herald rule "%s" is not valid, '. + 'or exceeded backtracking or recursion limits while '. + 'executing. Verify the expression and correct it or rewrite '. + 'it with less backtracking.', + $condition_value, + $rule->getMonogram()); + $message[] = $ex->getMessage(); + $message = implode("\n\n", $message); + + throw new HeraldInvalidConditionException($message); } + if ($result) { return $result_if_match; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/application/PhabricatorHeraldApplication.php phabricator-0~git20220903/phabricator/src/applications/herald/application/PhabricatorHeraldApplication.php --- phabricator-0~git20200925/phabricator/src/applications/herald/application/PhabricatorHeraldApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/application/PhabricatorHeraldApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -57,13 +57,13 @@ 'new/' => 'HeraldNewController', 'create/' => 'HeraldNewController', 'edit/(?:(?P<id>[1-9]\d*)/)?' => 'HeraldRuleController', - 'disable/(?P<id>[1-9]\d*)/(?P<action>\w+)/' + 'disable/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/' => 'HeraldDisableController', 'test/' => 'HeraldTestConsoleController', 'transcript/' => array( '' => 'HeraldTranscriptListController', '(?:query/(?P<queryKey>[^/]+)/)?' => 'HeraldTranscriptListController', - '(?P<id>[1-9]\d*)/' + '(?P<id>[1-9]\d*)/(?:(?P<view>[^/]+)/)?' => 'HeraldTranscriptController', ), 'webhook/' => array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/controller/HeraldRuleController.php phabricator-0~git20220903/phabricator/src/applications/herald/controller/HeraldRuleController.php --- phabricator-0~git20200925/phabricator/src/applications/herald/controller/HeraldRuleController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/controller/HeraldRuleController.php 2022-06-14 16:29:55.000000000 +0000 @@ -108,8 +108,7 @@ throw new Exception( pht( 'This rule was created with a newer version of Herald. You can not '. - 'view or edit it in this older version. Upgrade your Phabricator '. - 'deployment.')); + 'view or edit it in this older version. Upgrade your software.')); } // Upgrade rule version to our version, since we might add newly-defined diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/controller/HeraldTranscriptController.php phabricator-0~git20220903/phabricator/src/applications/herald/controller/HeraldTranscriptController.php --- phabricator-0~git20200925/phabricator/src/applications/herald/controller/HeraldTranscriptController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/controller/HeraldTranscriptController.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,6 +9,12 @@ return $this->adapter; } + public function buildApplicationMenu() { + // Use the menu we build in this controller, not the default menu for + // Herald. + return null; + } + public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); @@ -20,6 +26,13 @@ return new Aphront404Response(); } + $view_key = $this->getViewKey($request); + if (!$view_key) { + return new Aphront404Response(); + } + + $navigation = $this->newSideNavView($xscript, $view_key); + $object = $xscript->getObject(); require_celerity_resource('herald-test-css'); @@ -57,42 +70,21 @@ $handles = $this->loadViewerHandles($phids); $this->handles = $handles; - if ($xscript->getDryRun()) { - $notice = new PHUIInfoView(); - $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); - $notice->setTitle(pht('Dry Run')); - $notice->appendChild( - pht( - 'This was a dry run to test Herald rules, '. - 'no actions were executed.')); - $content[] = $notice; - } - $warning_panel = $this->buildWarningPanel($xscript); $content[] = $warning_panel; - $content[] = array( - $this->buildActionTranscriptPanel($xscript), - $this->buildObjectTranscriptPanel($xscript), - $this->buildTransactionsTranscriptPanel( - $object, - $xscript), - $this->buildProfilerTranscriptPanel($xscript), - ); + $content[] = $this->newContentView($xscript, $view_key); } $crumbs = id($this->buildApplicationCrumbs()) ->addTextCrumb( pht('Transcripts'), $this->getApplicationURI('/transcript/')) - ->addTextCrumb($xscript->getID()) + ->addTextCrumb(pht('Transcript %d', $xscript->getID())) ->setBorder(true); - $title = pht('Transcript: %s', $xscript->getID()); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-file'); + $title = pht('Herald Transcript %s', $xscript->getID()); + $header = $this->newHeaderView($xscript, $title); $view = id(new PHUITwoColumnView()) ->setHeader($header) @@ -101,10 +93,8 @@ return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->appendChild( - array( - $view, - )); + ->setNavigation($navigation) + ->appendChild($view); } protected function renderConditionTestValue($condition, $handles) { @@ -234,6 +224,7 @@ } private function buildActionTranscriptPanel(HeraldTranscript $xscript) { + $viewer = $this->getViewer(); $action_xscript = mgroup($xscript->getApplyTranscripts(), 'getRuleID'); $adapter = $this->getAdapter(); @@ -263,7 +254,9 @@ ->setHeader($rule_xscript->getRuleName()) ->setHref($rule_uri); - if (!$rule_xscript->getResult()) { + $rule_result = $rule_xscript->getRuleResult(); + + if (!$rule_result->getShouldApplyActions()) { $rule_item->setDisabled(true); } @@ -279,34 +272,20 @@ ->setTarget(phutil_tag('strong', array(), pht('Conditions')))); foreach ($cond_xscripts as $cond_xscript) { - if ($cond_xscript->isForbidden()) { - $icon = 'fa-ban'; - $color = 'indigo'; - $result = pht('Forbidden'); - } else if ($cond_xscript->getResult()) { - $icon = 'fa-check'; - $color = 'green'; - $result = pht('Passed'); - } else { - $icon = 'fa-times'; - $color = 'red'; - $result = pht('Failed'); - } - - if ($cond_xscript->getNote()) { - $note_text = $cond_xscript->getNote(); - if ($cond_xscript->isForbidden()) { - $note_text = HeraldStateReasons::getExplanation($note_text); - } + $result = $cond_xscript->getResult(); - $note = phutil_tag( + $icon = $result->getIconIcon(); + $color = $result->getIconColor(); + $name = $result->getName(); + + $result_details = $result->newDetailsView($viewer); + if ($result_details !== null) { + $result_details = phutil_tag( 'div', array( 'class' => 'herald-condition-note', ), - $note_text); - } else { - $note = null; + $result_details); } // TODO: This is not really translatable and should be driven through @@ -319,33 +298,33 @@ $cond_item = id(new PHUIStatusItemView()) ->setIcon($icon, $color) - ->setTarget($result) - ->setNote(array($explanation, $note)); + ->setTarget($name) + ->setNote(array($explanation, $result_details)); $cond_list->addItem($cond_item); } - if ($rule_xscript->isForbidden()) { - $last_icon = 'fa-ban'; - $last_color = 'indigo'; - $last_result = pht('Forbidden'); - $last_note = pht('Object state prevented rule evaluation.'); - } else if ($rule_xscript->getResult()) { - $last_icon = 'fa-check-circle'; - $last_color = 'green'; - $last_result = pht('Passed'); - $last_note = pht('Rule passed.'); - } else { - $last_icon = 'fa-times-circle'; - $last_color = 'red'; - $last_result = pht('Failed'); - $last_note = pht('Rule failed.'); + $rule_result = $rule_xscript->getRuleResult(); + + $last_icon = $rule_result->getIconIcon(); + $last_color = $rule_result->getIconColor(); + $last_result = $rule_result->getName(); + $last_note = $rule_result->getDescription(); + + $last_details = $rule_result->newDetailsView($viewer); + if ($last_details !== null) { + $last_details = phutil_tag( + 'div', + array( + 'class' => 'herald-condition-note', + ), + $last_details); } $cond_last = id(new PHUIStatusItemView()) ->setIcon($last_icon, $last_color) ->setTarget(phutil_tag('strong', array(), $last_result)) - ->setNote($last_note); + ->setNote(array($last_note, $last_details)); $cond_list->addItem($cond_last); $cond_box = id(new PHUIBoxView()) @@ -354,11 +333,10 @@ $rule_item->appendChild($cond_box); - if (!$rule_xscript->getResult()) { - // If the rule didn't pass, don't generate an action transcript since - // actions didn't apply. - continue; - } + // Not all rules will have any action transcripts, but we show them + // in general because they may have relevant information even when + // rules did not take actions. In particular, state-based actions may + // forbid rules from matching. $cond_box->addMargin(PHUI::MARGIN_MEDIUM_BOTTOM); @@ -443,7 +421,22 @@ ->setHeaderText(pht('Rule Transcript')) ->appendChild($rule_list); - return $box; + $content = array(); + + if ($xscript->getDryRun()) { + $notice = new PHUIInfoView(); + $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); + $notice->setTitle(pht('Dry Run')); + $notice->appendChild( + pht( + 'This was a dry run to test Herald rules, '. + 'no actions were executed.')); + $content[] = $notice; + } + + $content[] = $box; + + return $content; } private function buildObjectTranscriptPanel(HeraldTranscript $xscript) { @@ -520,35 +513,15 @@ return $box; } - private function buildTransactionsTranscriptPanel( - $object, - HeraldTranscript $xscript) { + private function buildTransactionsTranscriptPanel(HeraldTranscript $xscript) { $viewer = $this->getViewer(); - $object_xscript = $xscript->getObjectTranscript(); - - $xaction_phids = $object_xscript->getAppliedTransactionPHIDs(); - - // If the value is "null", this is an older transcript or this adapter - // does not use transactions. We render nothing. - // - // If the value is "array()", this is a modern transcript which uses - // transactions, there just weren't any applied. Below, we'll render a - // "No Transactions Applied" state. - if ($xaction_phids === null) { - return null; - } - - // If this object doesn't implement the right interface, we won't be - // able to load the transactions. Just bail. - if (!($object instanceof PhabricatorApplicationTransactionInterface)) { - return null; - } - - $query = PhabricatorApplicationTransactionQuery::newQueryForObject( - $object); + $xaction_phids = $this->getTranscriptTransactionPHIDs($xscript); if ($xaction_phids) { + $object = $xscript->getObject(); + $query = PhabricatorApplicationTransactionQuery::newQueryForObject( + $object); $xactions = $query ->setViewer($viewer) ->withPHIDs($xaction_phids) @@ -704,4 +677,128 @@ return $box_view; } + private function getViewKey(AphrontRequest $request) { + $view_key = $request->getURIData('view'); + + if ($view_key === null) { + return 'rules'; + } + + switch ($view_key) { + case 'fields': + case 'xactions': + case 'profile': + return $view_key; + default: + return null; + } + } + + private function newSideNavView( + HeraldTranscript $xscript, + $view_key) { + + $base_uri = urisprintf( + 'transcript/%d/', + $xscript->getID()); + + $base_uri = $this->getApplicationURI($base_uri); + $base_uri = new PhutilURI($base_uri); + + $nav = id(new AphrontSideNavFilterView()) + ->setBaseURI($base_uri); + + $nav->newLink('rules') + ->setHref($base_uri) + ->setName(pht('Rules')) + ->setIcon('fa-list-ul'); + + $nav->newLink('fields') + ->setName(pht('Field Values')) + ->setIcon('fa-file-text-o'); + + $xaction_phids = $this->getTranscriptTransactionPHIDs($xscript); + $has_xactions = (bool)$xaction_phids; + + $nav->newLink('xactions') + ->setName(pht('Transactions')) + ->setIcon('fa-forward') + ->setDisabled(!$has_xactions); + + $nav->newLink('profile') + ->setName(pht('Profiler')) + ->setIcon('fa-tachometer'); + + $nav->selectFilter($view_key); + + return $nav; + } + + private function newContentView( + HeraldTranscript $xscript, + $view_key) { + + switch ($view_key) { + case 'rules': + $content = $this->buildActionTranscriptPanel($xscript); + break; + case 'fields': + $content = $this->buildObjectTranscriptPanel($xscript); + break; + case 'xactions': + $content = $this->buildTransactionsTranscriptPanel($xscript); + break; + case 'profile': + $content = $this->buildProfilerTranscriptPanel($xscript); + break; + default: + throw new Exception(pht('Unknown view key "%s".', $view_key)); + } + + return $content; + } + + private function getTranscriptTransactionPHIDs(HeraldTranscript $xscript) { + + $object_xscript = $xscript->getObjectTranscript(); + $xaction_phids = $object_xscript->getAppliedTransactionPHIDs(); + + // If the value is "null", this is an older transcript or this adapter + // does not use transactions. + // + // (If the value is "array()", this is a modern transcript which uses + // transactions, there just weren't any applied.) + if ($xaction_phids === null) { + return array(); + } + + $object = $xscript->getObject(); + + // If this object doesn't implement the right interface, we won't be + // able to load the transactions. + if (!($object instanceof PhabricatorApplicationTransactionInterface)) { + return array(); + } + + return $xaction_phids; + } + + private function newHeaderView(HeraldTranscript $xscript, $title) { + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon('fa-list-ul'); + + if ($xscript->getDryRun()) { + $dry_run_tag = id(new PHUITagView()) + ->setType(PHUITagView::TYPE_SHADE) + ->setColor(PHUITagView::COLOR_VIOLET) + ->setName(pht('Dry Run')) + ->setIcon('fa-exclamation-triangle'); + + $header->addTag($dry_run_tag); + } + + return $header; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/controller/HeraldWebhookViewController.php phabricator-0~git20220903/phabricator/src/applications/herald/controller/HeraldWebhookViewController.php --- phabricator-0~git20200925/phabricator/src/applications/herald/controller/HeraldWebhookViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/controller/HeraldWebhookViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -53,7 +53,7 @@ $warnings = array(); if (PhabricatorEnv::getEnvConfig('phabricator.silent')) { $message = pht( - 'Phabricator is currently configured in silent mode, so it will not '. + 'This server is running in silent mode, so it will not '. 'publish webhooks. To adjust this setting, see '. '@{config:phabricator.silent} in Config.'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/engine/exception/HeraldRuleEvaluationException.php phabricator-0~git20220903/phabricator/src/applications/herald/engine/exception/HeraldRuleEvaluationException.php --- phabricator-0~git20200925/phabricator/src/applications/herald/engine/exception/HeraldRuleEvaluationException.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/engine/exception/HeraldRuleEvaluationException.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,3 @@ +<?php + +final class HeraldRuleEvaluationException extends Exception {} diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/engine/HeraldEngine.php phabricator-0~git20220903/phabricator/src/applications/herald/engine/HeraldEngine.php --- phabricator-0~git20200925/phabricator/src/applications/herald/engine/HeraldEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/engine/HeraldEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -3,12 +3,11 @@ final class HeraldEngine extends Phobject { protected $rules = array(); - protected $results = array(); - protected $stack = array(); protected $activeRule; protected $transcript; - protected $fieldCache = array(); + private $fieldCache = array(); + private $fieldExceptions = array(); protected $object; private $dryRun; @@ -19,6 +18,9 @@ private $profilerStack = array(); private $profilerFrames = array(); + private $ruleResults; + private $ruleStack; + public function setDryRun($dry_run) { $this->dryRun = $dry_run; return $this; @@ -53,6 +55,74 @@ return $engine->getTranscript(); } +/* -( Rule Stack )--------------------------------------------------------- */ + + private function resetRuleStack() { + $this->ruleStack = array(); + return $this; + } + + private function hasRuleOnStack(HeraldRule $rule) { + $phid = $rule->getPHID(); + return isset($this->ruleStack[$phid]); + } + + private function pushRuleStack(HeraldRule $rule) { + $phid = $rule->getPHID(); + $this->ruleStack[$phid] = $rule; + return $this; + } + + private function getRuleStack() { + return array_values($this->ruleStack); + } + +/* -( Rule Results )------------------------------------------------------- */ + + private function resetRuleResults() { + $this->ruleResults = array(); + return $this; + } + + private function setRuleResult( + HeraldRule $rule, + HeraldRuleResult $result) { + + $phid = $rule->getPHID(); + + if ($this->hasRuleResult($rule)) { + throw new Exception( + pht( + 'Herald rule "%s" already has an evaluation result.', + $phid)); + } + + $this->ruleResults[$phid] = $result; + + $this->newRuleTranscript($rule) + ->setRuleResult($result); + + return $this; + } + + private function hasRuleResult(HeraldRule $rule) { + $phid = $rule->getPHID(); + return isset($this->ruleResults[$phid]); + } + + private function getRuleResult(HeraldRule $rule) { + $phid = $rule->getPHID(); + + if (!$this->hasRuleResult($rule)) { + throw new Exception( + pht( + 'Herald rule "%s" does not have an evaluation result.', + $phid)); + } + + return $this->ruleResults[$phid]; + } + public function applyRules(array $rules, HeraldAdapter $object) { assert_instances_of($rules, 'HeraldRule'); $t_start = microtime(true); @@ -64,65 +134,98 @@ $this->transcript = new HeraldTranscript(); $this->transcript->setObjectPHID((string)$object->getPHID()); $this->fieldCache = array(); - $this->results = array(); + $this->fieldExceptions = array(); $this->rules = $rules; $this->object = $object; + $this->resetRuleResults(); + $effects = array(); foreach ($rules as $phid => $rule) { - $this->stack = array(); - - $is_first_only = $rule->isRepeatFirst(); + $this->resetRuleStack(); + $caught = null; + $result = null; try { + $is_first_only = $rule->isRepeatFirst(); + if (!$this->getDryRun() && $is_first_only && $rule->getRuleApplied($object->getPHID())) { + // This is not a dry run, and this rule is only supposed to be - // applied a single time, and it's already been applied... + // applied a single time, and it has already been applied. // That means automatic failure. - $this->newRuleTranscript($rule) - ->setResult(false) - ->setReason( - pht( - 'This rule is only supposed to be repeated a single time, '. - 'and it has already been applied.')); - $rule_matches = false; + $result_code = HeraldRuleResult::RESULT_ALREADY_APPLIED; + $result = HeraldRuleResult::newFromResultCode($result_code); + } else if ($this->isForbidden($rule, $object)) { + $result_code = HeraldRuleResult::RESULT_OBJECT_STATE; + $result = HeraldRuleResult::newFromResultCode($result_code); } else { - if ($this->isForbidden($rule, $object)) { - $this->newRuleTranscript($rule) - ->setResult(HeraldRuleTranscript::RESULT_FORBIDDEN) - ->setReason( - pht( - 'Object state is not compatible with rule.')); - - $rule_matches = false; - } else { - $rule_matches = $this->doesRuleMatch($rule, $object); - } + $result = $this->getRuleMatchResult($rule, $object); } } catch (HeraldRecursiveConditionsException $ex) { - $names = array(); - foreach ($this->stack as $rule_phid => $ignored) { - $names[] = '"'.$rules[$rule_phid]->getName().'"'; - } - $names = implode(', ', $names); - foreach ($this->stack as $rule_phid => $ignored) { - $this->newRuleTranscript($rules[$rule_phid]) - ->setResult(false) - ->setReason( - pht( - "Rules %s are recursively dependent upon one another! ". - "Don't do this! You have formed an unresolvable cycle in the ". - "dependency graph!", - $names)); - } - $rule_matches = false; + $cycle_phids = array(); + + $stack = $this->getRuleStack(); + foreach ($stack as $stack_rule) { + $cycle_phids[] = $stack_rule->getPHID(); + } + // Add the rule which actually cycled to the list to make the + // result more clear when we show it to the user. + $cycle_phids[] = $phid; + + foreach ($stack as $stack_rule) { + if ($this->hasRuleResult($stack_rule)) { + continue; + } + + $result_code = HeraldRuleResult::RESULT_RECURSION; + $result_data = array( + 'cyclePHIDs' => $cycle_phids, + ); + + $result = HeraldRuleResult::newFromResultCode($result_code) + ->setResultData($result_data); + $this->setRuleResult($stack_rule, $result); + } + + $result = $this->getRuleResult($rule); + } catch (HeraldRuleEvaluationException $ex) { + // When we encounter an evaluation exception, the condition which + // failed to evaluate is responsible for logging the details of the + // error. + + $result_code = HeraldRuleResult::RESULT_EVALUATION_EXCEPTION; + $result = HeraldRuleResult::newFromResultCode($result_code); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; } - $this->results[$phid] = $rule_matches; - if ($rule_matches) { + if ($caught) { + // These exceptions are unexpected, and did not arise during rule + // evaluation, so we're responsible for handling the details. + + $result_code = HeraldRuleResult::RESULT_EXCEPTION; + + $result_data = array( + 'exception.class' => get_class($caught), + 'exception.message' => $ex->getMessage(), + ); + + $result = HeraldRuleResult::newFromResultCode($result_code) + ->setResultData($result_data); + } + + if (!$this->hasRuleResult($rule)) { + $this->setRuleResult($rule, $result); + } + $result = $this->getRuleResult($rule); + + if ($result->getShouldApplyActions()) { foreach ($this->getRuleEffects($rule, $object) as $effect) { $effects[] = $effect; } @@ -269,213 +372,296 @@ public function doesRuleMatch( HeraldRule $rule, HeraldAdapter $object) { + $result = $this->getRuleMatchResult($rule, $object); + return $result->getShouldApplyActions(); + } - $phid = $rule->getPHID(); + private function getRuleMatchResult( + HeraldRule $rule, + HeraldAdapter $object) { - if (isset($this->results[$phid])) { + if ($this->hasRuleResult($rule)) { // If we've already evaluated this rule because another rule depends // on it, we don't need to reevaluate it. - return $this->results[$phid]; + return $this->getRuleResult($rule); } - if (isset($this->stack[$phid])) { + if ($this->hasRuleOnStack($rule)) { // We've recursed, fail all of the rules on the stack. This happens when // there's a dependency cycle with "Rule conditions match for rule ..." // conditions. - foreach ($this->stack as $rule_phid => $ignored) { - $this->results[$rule_phid] = false; - } throw new HeraldRecursiveConditionsException(); } - - $this->stack[$phid] = true; + $this->pushRuleStack($rule); $all = $rule->getMustMatchAll(); $conditions = $rule->getConditions(); - $result = null; + $result_code = null; + $result_data = array(); $local_version = id(new HeraldRule())->getConfigVersion(); if ($rule->getConfigVersion() > $local_version) { - $reason = pht( - 'Rule could not be processed, it was created with a newer version '. - 'of Herald.'); - $result = false; + $result_code = HeraldRuleResult::RESULT_VERSION; } else if (!$conditions) { - $reason = pht( - 'Rule failed automatically because it has no conditions.'); - $result = false; + $result_code = HeraldRuleResult::RESULT_EMPTY; } else if (!$rule->hasValidAuthor()) { - $reason = pht( - 'Rule failed automatically because its owner is invalid '. - 'or disabled.'); - $result = false; + $result_code = HeraldRuleResult::RESULT_OWNER; } else if (!$this->canAuthorViewObject($rule, $object)) { - $reason = pht( - 'Rule failed automatically because it is a personal rule and its '. - 'owner can not see the object.'); - $result = false; + $result_code = HeraldRuleResult::RESULT_VIEW_POLICY; } else if (!$this->canRuleApplyToObject($rule, $object)) { - $reason = pht( - 'Rule failed automatically because it is an object rule which is '. - 'not relevant for this object.'); - $result = false; + $result_code = HeraldRuleResult::RESULT_OBJECT_RULE; } else { foreach ($conditions as $condition) { - try { - $this->getConditionObjectValue($condition, $object); - } catch (Exception $ex) { - $reason = pht( - 'Field "%s" does not exist!', - $condition->getFieldName()); - $result = false; - break; - } - - // Here, we're profiling the cost to match the condition value against - // whatever test is configured. Normally, this cost should be very - // small (<<1ms) since it amounts to a single comparison: - // - // [ Task author ][ is any of ][ alice ] - // - // However, it may be expensive in some cases, particularly if you - // write a rule with a very creative regular expression that backtracks - // explosively. - // - // At time of writing, the "Another Herald Rule" field is also - // evaluated inside the matching function. This may be arbitrarily - // expensive (it can prompt us to execute any finite number of other - // Herald rules), although we'll push the profiler stack appropriately - // so we don't count the evaluation time against this rule in the final - // profile. - $caught = null; - $this->pushProfilerRule($rule); try { - $match = $this->doesConditionMatch($rule, $condition, $object); + $match = $this->doesConditionMatch( + $rule, + $condition, + $object); + } catch (HeraldRuleEvaluationException $ex) { + throw $ex; + } catch (HeraldRecursiveConditionsException $ex) { + throw $ex; } catch (Exception $ex) { $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; } - $this->popProfilerRule($rule); if ($caught) { - throw $ex; + throw new HeraldRuleEvaluationException(); } if (!$all && $match) { - $reason = pht('Any condition matched.'); - $result = true; + $result_code = HeraldRuleResult::RESULT_ANY_MATCHED; break; } if ($all && !$match) { - $reason = pht('Not all conditions matched.'); - $result = false; + $result_code = HeraldRuleResult::RESULT_ANY_FAILED; break; } } - if ($result === null) { + if ($result_code === null) { if ($all) { - $reason = pht('All conditions matched.'); - $result = true; + $result_code = HeraldRuleResult::RESULT_ALL_MATCHED; } else { - $reason = pht('No conditions matched.'); - $result = false; + $result_code = HeraldRuleResult::RESULT_ALL_FAILED; } } } // If this rule matched, and is set to run "if it did not match the last - // time", and we matched the last time, we're going to return a match in - // the transcript but set a flag so we don't actually apply any effects. + // time", and we matched the last time, we're going to return a special + // result code which records a match but doesn't actually apply effects. // We need the rule to match so that storage gets updated properly. If we // just pretend the rule didn't match it won't cause any effects (which // is correct), but it also won't set the "it matched" flag in storage, // so the next run after this one would incorrectly trigger again. + $result = HeraldRuleResult::newFromResultCode($result_code) + ->setResultData($result_data); + + $should_apply = $result->getShouldApplyActions(); + $is_dry_run = $this->getDryRun(); - if ($result && !$is_dry_run) { + if ($should_apply && !$is_dry_run) { $is_on_change = $rule->isRepeatOnChange(); if ($is_on_change) { $did_apply = $rule->getRuleApplied($object->getPHID()); if ($did_apply) { - $reason = pht( - 'This rule matched, but did not take any actions because it '. - 'is configured to act only if it did not match the last time.'); + // Replace the result with our modified result. + $result_code = HeraldRuleResult::RESULT_LAST_MATCHED; + $result = HeraldRuleResult::newFromResultCode($result_code); $this->skipEffects[$rule->getID()] = true; } } } - $this->newRuleTranscript($rule) - ->setResult($result) - ->setReason($reason); + $this->setRuleResult($rule, $result); return $result; } - protected function doesConditionMatch( + private function doesConditionMatch( HeraldRule $rule, HeraldCondition $condition, - HeraldAdapter $object) { + HeraldAdapter $adapter) { - $object_value = $this->getConditionObjectValue($condition, $object); $transcript = $this->newConditionTranscript($rule, $condition); + $caught = null; + $result_data = array(); + try { - $result = $object->doesConditionMatch( - $this, + $field_key = $condition->getFieldName(); + + $field_value = $this->getProfiledObjectFieldValue( + $adapter, + $field_key); + + $is_match = $this->getProfiledConditionMatch( + $adapter, $rule, $condition, - $object_value); + $field_value); + if ($is_match) { + $result_code = HeraldConditionResult::RESULT_MATCHED; + } else { + $result_code = HeraldConditionResult::RESULT_FAILED; + } + } catch (HeraldRecursiveConditionsException $ex) { + $result_code = HeraldConditionResult::RESULT_RECURSION; + $caught = $ex; } catch (HeraldInvalidConditionException $ex) { - $result = false; - $transcript->setNote($ex->getMessage()); + $result_code = HeraldConditionResult::RESULT_INVALID; + $caught = $ex; + } catch (Exception $ex) { + $result_code = HeraldConditionResult::RESULT_EXCEPTION; + $caught = $ex; + } catch (Throwable $ex) { + $result_code = HeraldConditionResult::RESULT_EXCEPTION; + $caught = $ex; + } + + if ($caught) { + $result_data = array( + 'exception.class' => get_class($caught), + 'exception.message' => $ex->getMessage(), + ); } + $result = HeraldConditionResult::newFromResultCode($result_code) + ->setResultData($result_data); + $transcript->setResult($result); - return $result; + if ($caught) { + throw $caught; + } + + return $result->getIsMatch(); } - protected function getConditionObjectValue( + private function getProfiledConditionMatch( + HeraldAdapter $adapter, + HeraldRule $rule, HeraldCondition $condition, - HeraldAdapter $object) { + $field_value) { + + // Here, we're profiling the cost to match the condition value against + // whatever test is configured. Normally, this cost should be very + // small (<<1ms) since it amounts to a single comparison: + // + // [ Task author ][ is any of ][ alice ] + // + // However, it may be expensive in some cases, particularly if you + // write a rule with a very creative regular expression that backtracks + // explosively. + // + // At time of writing, the "Another Herald Rule" field is also + // evaluated inside the matching function. This may be arbitrarily + // expensive (it can prompt us to execute any finite number of other + // Herald rules), although we'll push the profiler stack appropriately + // so we don't count the evaluation time against this rule in the final + // profile. - $field = $condition->getFieldName(); + $this->pushProfilerRule($rule); - return $this->getObjectFieldValue($field); + $caught = null; + try { + $is_match = $adapter->doesConditionMatch( + $this, + $rule, + $condition, + $field_value); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + $this->popProfilerRule($rule); + + if ($caught) { + throw $caught; + } + + return $is_match; } - public function getObjectFieldValue($field) { - if (!array_key_exists($field, $this->fieldCache)) { - $adapter = $this->object; + private function getProfiledObjectFieldValue( + HeraldAdapter $adapter, + $field_key) { - $adapter->willGetHeraldField($field); + // Before engaging the profiler, make sure the field class is loaded. - $caught = null; + $adapter->willGetHeraldField($field_key); - $this->pushProfilerField($field); - try { - $value = $adapter->getHeraldField($field); - } catch (Exception $ex) { - $caught = $ex; - } - $this->popProfilerField($field); + // The first time we read a field value, we'll actually generate it, which + // may be slow. - if ($caught) { - throw $caught; - } + // After it is generated for the first time, this will just read it from a + // cache, which should be very fast. + + // We still want to profile the request even if it goes to cache so we can + // get an accurate count of how many times we access the field value: when + // trying to improve the performance of Herald rules, it's helpful to know + // how many rules rely on the value of a field which is slow to generate. + + $caught = null; + + $this->pushProfilerField($field_key); + try { + $value = $this->getObjectFieldValue($field_key); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + $this->popProfilerField($field_key); - $this->fieldCache[$field] = $value; + if ($caught) { + throw $caught; } - return $this->fieldCache[$field]; + return $value; + } + + private function getObjectFieldValue($field_key) { + if (array_key_exists($field_key, $this->fieldExceptions)) { + throw $this->fieldExceptions[$field_key]; + } + + if (array_key_exists($field_key, $this->fieldCache)) { + return $this->fieldCache[$field_key]; + } + + $adapter = $this->object; + + $caught = null; + try { + $value = $adapter->getHeraldField($field_key); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + if ($caught) { + $this->fieldExceptions[$field_key] = $caught; + throw $caught; + } + + $this->fieldCache[$field_key] = $value; + + return $value; } protected function getRuleEffects( @@ -639,9 +825,16 @@ $forbidden_reason = $this->forbiddenFields[$field_key]; if ($forbidden_reason !== null) { + $result_code = HeraldConditionResult::RESULT_OBJECT_STATE; + $result_data = array( + 'reason' => $forbidden_reason, + ); + + $result = HeraldConditionResult::newFromResultCode($result_code) + ->setResultData($result_data); + $this->newConditionTranscript($rule, $condition) - ->setResult(HeraldConditionTranscript::RESULT_FORBIDDEN) - ->setNote($forbidden_reason); + ->setResult($result); $is_forbidden = true; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/field/HeraldCommentContentField.php phabricator-0~git20220903/phabricator/src/applications/herald/field/HeraldCommentContentField.php --- phabricator-0~git20200925/phabricator/src/applications/herald/field/HeraldCommentContentField.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/field/HeraldCommentContentField.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,43 @@ +<?php + +final class HeraldCommentContentField extends HeraldField { + + const FIELDCONST = 'comment.content'; + + public function getHeraldFieldName() { + return pht('Comment content'); + } + + public function getFieldGroupKey() { + return HeraldTransactionsFieldGroup::FIELDGROUPKEY; + } + + public function getHeraldFieldValue($object) { + $adapter = $this->getAdapter(); + + $xactions = $adapter->getAppliedTransactions(); + + $result = array(); + foreach ($xactions as $xaction) { + if (!$xaction->hasComment()) { + continue; + } + + $comment = $xaction->getComment(); + $content = $comment->getContent(); + + $result[] = $content; + } + + return $result; + } + + public function supportsObject($object) { + return true; + } + + protected function getHeraldFieldStandardType() { + return self::STANDARD_TEXT_LIST; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/query/HeraldRuleQuery.php phabricator-0~git20220903/phabricator/src/applications/herald/query/HeraldRuleQuery.php --- phabricator-0~git20200925/phabricator/src/applications/herald/query/HeraldRuleQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/query/HeraldRuleQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -86,10 +86,6 @@ return new HeraldRule(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $rules) { $rule_ids = mpull($rules, 'getID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/query/HeraldWebhookQuery.php phabricator-0~git20220903/phabricator/src/applications/herald/query/HeraldWebhookQuery.php --- phabricator-0~git20200925/phabricator/src/applications/herald/query/HeraldWebhookQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/query/HeraldWebhookQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new HeraldWebhook(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/query/HeraldWebhookRequestQuery.php phabricator-0~git20220903/phabricator/src/applications/herald/query/HeraldWebhookRequestQuery.php --- phabricator-0~git20200925/phabricator/src/applications/herald/query/HeraldWebhookRequestQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/query/HeraldWebhookRequestQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -29,10 +29,6 @@ return new HeraldWebhookRequest(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - public function withLastRequestEpochBetween($epoch_min, $epoch_max) { $this->lastRequestEpochMin = $epoch_min; $this->lastRequestEpochMax = $epoch_max; diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldConditionResult.php phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldConditionResult.php --- phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldConditionResult.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldConditionResult.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,113 @@ +<?php + +final class HeraldConditionResult + extends HeraldTranscriptResult { + + const RESULT_MATCHED = 'matched'; + const RESULT_FAILED = 'failed'; + const RESULT_OBJECT_STATE = 'object-state'; + const RESULT_INVALID = 'invalid'; + const RESULT_RECURSION = 'recursion'; + const RESULT_EXCEPTION = 'exception'; + const RESULT_UNKNOWN = 'unknown'; + + public static function newFromResultCode($result_code) { + return id(new self())->setResultCode($result_code); + } + + public static function newFromResultMap(array $map) { + return id(new self())->loadFromResultMap($map); + } + + public function getIsMatch() { + return ($this->getSpecificationProperty('match') === true); + } + + public function newDetailsView(PhabricatorUser $viewer) { + switch ($this->getResultCode()) { + case self::RESULT_OBJECT_STATE: + $reason = $this->getDataProperty('reason'); + $details = HeraldStateReasons::getExplanation($reason); + break; + case self::RESULT_INVALID: + case self::RESULT_EXCEPTION: + $error_class = $this->getDataProperty('exception.class'); + $error_message = $this->getDataProperty('exception.message'); + + if (!strlen($error_class)) { + $error_class = pht('Unknown Error'); + } + + switch ($error_class) { + case 'HeraldInvalidConditionException': + $error_class = pht('Invalid Condition'); + break; + } + + if (!strlen($error_message)) { + $error_message = pht( + 'An unknown error occurred while evaluating this condition. No '. + 'additional information is available.'); + } + + $details = pht( + '%s: %s', + phutil_tag('strong', array(), $error_class), + phutil_escape_html_newlines($error_message)); + break; + default: + $details = null; + break; + } + + return $details; + } + + protected function newResultSpecificationMap() { + return array( + self::RESULT_MATCHED => array( + 'match' => true, + 'icon' => 'fa-check', + 'color.icon' => 'green', + 'name' => pht('Passed'), + ), + self::RESULT_FAILED => array( + 'match' => false, + 'icon' => 'fa-times', + 'color.icon' => 'red', + 'name' => pht('Failed'), + ), + self::RESULT_OBJECT_STATE => array( + 'match' => null, + 'icon' => 'fa-ban', + 'color.icon' => 'indigo', + 'name' => pht('Forbidden'), + ), + self::RESULT_INVALID => array( + 'match' => null, + 'icon' => 'fa-exclamation-triangle', + 'color.icon' => 'yellow', + 'name' => pht('Invalid'), + ), + self::RESULT_RECURSION => array( + 'match' => null, + 'icon' => 'fa-exclamation-triangle', + 'color.icon' => 'red', + 'name' => pht('Recursion'), + ), + self::RESULT_EXCEPTION => array( + 'match' => null, + 'icon' => 'fa-exclamation-triangle', + 'color.icon' => 'red', + 'name' => pht('Exception'), + ), + self::RESULT_UNKNOWN => array( + 'match' => null, + 'icon' => 'fa-question', + 'color.icon' => 'grey', + 'name' => pht('Unknown'), + ), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldConditionTranscript.php phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldConditionTranscript.php --- phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldConditionTranscript.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldConditionTranscript.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,10 +7,17 @@ protected $fieldName; protected $condition; protected $testValue; - protected $note; - protected $result; + protected $resultMap; - const RESULT_FORBIDDEN = 'forbidden'; + // See T13586. Older versions of this record stored a boolean true, boolean + // false, or the string "forbidden" in the "$result" field. They stored a + // human-readable English-language message or a state code in the "$note" + // field. + + // The modern record does not use either field. + + protected $result; + protected $note; public function setRuleID($rule_id) { $this->ruleID = $rule_id; @@ -57,26 +64,39 @@ return $this->testValue; } - public function setNote($note) { - $this->note = $note; - return $this; - } - - public function getNote() { - return $this->note; - } - - public function setResult($result) { - $this->result = $result; + public function setResult(HeraldConditionResult $result) { + $this->resultMap = $result->newResultMap(); return $this; } public function getResult() { - return $this->result; - } + $map = $this->resultMap; + + if (is_array($map)) { + $result = HeraldConditionResult::newFromResultMap($map); + } else { + $legacy_result = $this->result; + + $result_data = array(); + + if ($legacy_result === 'forbidden') { + $result_code = HeraldConditionResult::RESULT_OBJECT_STATE; + $result_data = array( + 'reason' => $this->note, + ); + } else if ($legacy_result === true) { + $result_code = HeraldConditionResult::RESULT_MATCHED; + } else if ($legacy_result === false) { + $result_code = HeraldConditionResult::RESULT_FAILED; + } else { + $result_code = HeraldConditionResult::RESULT_UNKNOWN; + } + + $result = HeraldConditionResult::newFromResultCode($result_code) + ->setResultData($result_data); + } - public function isForbidden() { - return ($this->getResult() === self::RESULT_FORBIDDEN); + return $result; } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldRuleResult.php phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldRuleResult.php --- phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldRuleResult.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldRuleResult.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,238 @@ +<?php + +final class HeraldRuleResult + extends HeraldTranscriptResult { + + const RESULT_ANY_MATCHED = 'any-match'; + const RESULT_ALL_MATCHED = 'all-match'; + const RESULT_ANY_FAILED = 'any-failed'; + const RESULT_ALL_FAILED = 'all-failed'; + const RESULT_LAST_MATCHED = 'last-match'; + const RESULT_VERSION = 'version'; + const RESULT_EMPTY = 'empty'; + const RESULT_OWNER = 'owner'; + const RESULT_VIEW_POLICY = 'view-policy'; + const RESULT_OBJECT_RULE = 'object-rule'; + const RESULT_EXCEPTION = 'exception'; + const RESULT_EVALUATION_EXCEPTION = 'evaluation-exception'; + const RESULT_UNKNOWN = 'unknown'; + const RESULT_ALREADY_APPLIED = 'already-applied'; + const RESULT_OBJECT_STATE = 'object-state'; + const RESULT_RECURSION = 'recursion'; + + public static function newFromResultCode($result_code) { + return id(new self())->setResultCode($result_code); + } + + public static function newFromResultMap(array $map) { + return id(new self())->loadFromResultMap($map); + } + + public function getShouldRecordMatch() { + return ($this->getSpecificationProperty('match') === true); + } + + public function getShouldApplyActions() { + return ($this->getSpecificationProperty('apply') === true); + } + + public function getDescription() { + return $this->getSpecificationProperty('description'); + } + + public function newDetailsView(PhabricatorUser $viewer) { + switch ($this->getResultCode()) { + case self::RESULT_EXCEPTION: + $error_class = $this->getDataProperty('exception.class'); + $error_message = $this->getDataProperty('exception.message'); + + if (!strlen($error_class)) { + $error_class = pht('Unknown Error'); + } + + if (!strlen($error_message)) { + $error_message = pht( + 'An unknown error occurred while evaluating this condition. No '. + 'additional information is available.'); + } + + $details = $this->newErrorView($error_class, $error_message); + break; + case self::RESULT_RECURSION: + $rule_phids = $this->getDataProperty('cyclePHIDs', array()); + $handles = $viewer->loadHandles($rule_phids); + + $links = array(); + foreach ($rule_phids as $rule_phid) { + $links[] = $handles[$rule_phid]->renderLink(); + } + + $links = phutil_implode_html(' > ', $links); + + $details = array( + pht('This rule has a dependency cycle and can not be evaluated:'), + ' ', + $links, + ); + break; + default: + $details = null; + break; + } + + return $details; + } + + protected function newResultSpecificationMap() { + return array( + self::RESULT_ANY_MATCHED => array( + 'match' => true, + 'apply' => true, + 'name' => pht('Matched'), + 'description' => pht('Any condition matched.'), + 'icon' => 'fa-check-circle', + 'color.icon' => 'green', + ), + self::RESULT_ALL_MATCHED => array( + 'match' => true, + 'apply' => true, + 'name' => pht('Matched'), + 'description' => pht('All conditions matched.'), + 'icon' => 'fa-check-circle', + 'color.icon' => 'green', + ), + self::RESULT_ANY_FAILED => array( + 'match' => false, + 'apply' => false, + 'name' => pht('Failed'), + 'description' => pht('Not all conditions matched.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_ALL_FAILED => array( + 'match' => false, + 'apply' => false, + 'name' => pht('Failed'), + 'description' => pht('No conditions matched.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_LAST_MATCHED => array( + 'match' => true, + 'apply' => false, + 'name' => pht('Failed'), + 'description' => pht( + 'This rule matched, but did not take any actions because it '. + 'is configured to act only if it did not match the last time.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_VERSION => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Version Issue'), + 'description' => pht( + 'Rule could not be processed because it was created with a newer '. + 'version of Herald.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_EMPTY => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Empty'), + 'description' => pht( + 'Rule failed automatically because it has no conditions.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_OWNER => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Rule Owner'), + 'description' => pht( + 'Rule failed automatically because it is a personal rule and '. + 'its owner is invalid or disabled.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_VIEW_POLICY => array( + 'match' => null, + 'apply' => false, + 'name' => pht('View Policy'), + 'description' => pht( + 'Rule failed automatically because it is a personal rule and '. + 'its owner does not have permission to view the object.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_OBJECT_RULE => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Object Rule'), + 'description' => pht( + 'Rule failed automatically because it is an object rule which is '. + 'not relevant for this object.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_EXCEPTION => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Exception'), + 'description' => pht( + 'Rule failed because an exception occurred.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_EVALUATION_EXCEPTION => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Exception'), + 'description' => pht( + 'Rule failed because an exception occurred while evaluating it.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_UNKNOWN => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Unknown'), + 'description' => pht( + 'Rule evaluation result is unknown.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_ALREADY_APPLIED => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Already Applied'), + 'description' => pht( + 'This rule is only supposed to be repeated a single time, '. + 'and it has already been applied.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + self::RESULT_OBJECT_STATE => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Forbidden'), + 'description' => pht( + 'Object state prevented rule evaluation.'), + 'icon' => 'fa-ban', + 'color.icon' => 'indigo', + ), + self::RESULT_RECURSION => array( + 'match' => null, + 'apply' => false, + 'name' => pht('Recursion'), + 'description' => pht( + 'This rule has a recursive dependency on itself and can not '. + 'be evaluated.'), + 'icon' => 'fa-times-circle', + 'color.icon' => 'red', + ), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldRuleTranscript.php phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldRuleTranscript.php --- phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldRuleTranscript.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldRuleTranscript.php 2022-06-14 16:29:55.000000000 +0000 @@ -3,35 +3,18 @@ final class HeraldRuleTranscript extends Phobject { protected $ruleID; - protected $result; - protected $reason; - + protected $ruleResultMap; protected $ruleName; protected $ruleOwner; - const RESULT_FORBIDDEN = 'forbidden'; - - public function isForbidden() { - return ($this->getResult() === self::RESULT_FORBIDDEN); - } - - public function setResult($result) { - $this->result = $result; - return $this; - } - - public function getResult() { - return $this->result; - } - - public function setReason($reason) { - $this->reason = $reason; - return $this; - } + // See T13586. This no longer has readers, but was written by older versions + // of Herald. It contained a human readable English-language description of + // the outcome of rule evaluation and was superseded by "HeraldRuleResult". + protected $reason; - public function getReason() { - return $this->reason; - } + // See T13586. Older transcripts store a boolean "true", a boolean "false", + // or the string "forbidden" here. + protected $result; public function setRuleID($rule_id) { $this->ruleID = $rule_id; @@ -59,4 +42,40 @@ public function getRuleOwner() { return $this->ruleOwner; } + + public function setRuleResult(HeraldRuleResult $result) { + $this->ruleResultMap = $result->newResultMap(); + return $this; + } + + public function getRuleResult() { + $map = $this->ruleResultMap; + + if (is_array($map)) { + $result = HeraldRuleResult::newFromResultMap($map); + } else { + $legacy_result = $this->result; + + $result_data = array(); + + if ($legacy_result === 'forbidden') { + $result_code = HeraldRuleResult::RESULT_OBJECT_STATE; + $result_data = array( + 'reason' => $this->reason, + ); + } else if ($legacy_result === true) { + $result_code = HeraldRuleResult::RESULT_ANY_MATCHED; + } else if ($legacy_result === false) { + $result_code = HeraldRuleResult::RESULT_ANY_FAILED; + } else { + $result_code = HeraldRuleResult::RESULT_UNKNOWN; + } + + $result = HeraldRuleResult::newFromResultCode($result_code) + ->setResultData($result_data); + } + + return $result; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldTranscript.php phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldTranscript.php --- phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldTranscript.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldTranscript.php 2022-06-14 16:29:55.000000000 +0000 @@ -66,6 +66,10 @@ } private static function combineXHeraldRulesHeaders($u, $v) { + if ($u === null) { + return $v; + } + $u = preg_split('/[, ]+/', $u); $v = preg_split('/[, ]+/', $v); diff -Nru phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldTranscriptResult.php phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldTranscriptResult.php --- phabricator-0~git20200925/phabricator/src/applications/herald/storage/transcript/HeraldTranscriptResult.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/herald/storage/transcript/HeraldTranscriptResult.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,91 @@ +<?php + +abstract class HeraldTranscriptResult + extends Phobject { + + private $resultCode; + private $resultData = array(); + + final protected function setResultCode($result_code) { + $this->resultCode = $result_code; + return $this; + } + + final protected function loadFromResultMap(array $map) { + $result_code = idx($map, 'code'); + $result_data = idx($map, 'data', array()); + + $this + ->setResultCode($result_code) + ->setResultData($result_data); + + return $this; + } + + final public function getResultCode() { + return $this->resultCode; + } + + final protected function getResultData() { + return $this->resultData; + } + + final public function setResultData(array $result_data) { + $this->resultData = $result_data; + return $this; + } + + final public function getIconIcon() { + return $this->getSpecificationProperty('icon'); + } + + final public function getIconColor() { + return $this->getSpecificationProperty('color.icon'); + } + + final public function getName() { + return $this->getSpecificationProperty('name'); + } + + abstract public function newDetailsView(PhabricatorUser $viewer); + + final protected function getDataProperty($key, $default = null) { + $data = $this->getResultData(); + return idx($data, $key, $default); + } + + final public function newResultMap() { + return array( + 'code' => $this->getResultCode(), + 'data' => $this->getResultData(), + ); + } + + final protected function getSpecificationProperty($key) { + $map = $this->getResultSpecification($this->getResultCode()); + return $map[$key]; + } + + final protected function getResultSpecification($result_code) { + $map = $this->newResultSpecificationMap(); + + if (!isset($map[$result_code])) { + throw new Exception( + pht( + 'Result code "%s" is unknown.', + $result_code)); + } + + return $map[$result_code]; + } + + abstract protected function newResultSpecificationMap(); + + final protected function newErrorView($error_class, $error_message) { + return pht( + '%s: %s', + phutil_tag('strong', array(), $error_class), + phutil_escape_html_newlines($error_message)); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/legalpad/controller/LegalpadDocumentSignController.php phabricator-0~git20220903/phabricator/src/applications/legalpad/controller/LegalpadDocumentSignController.php --- phabricator-0~git20200925/phabricator/src/applications/legalpad/controller/LegalpadDocumentSignController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/legalpad/controller/LegalpadDocumentSignController.php 2022-06-14 16:29:55.000000000 +0000 @@ -681,7 +681,7 @@ $body = pht( "%s:\n\n". "This email address was used to sign a Legalpad document ". - "in Phabricator:\n\n". + "in %s:\n\n". " %s\n\n". "Please verify you own this email address and accept the ". "agreement by clicking this link:\n\n". @@ -690,6 +690,7 @@ "verification step.\n\nYou can review the document here:\n\n". " %s\n", $name, + PlatformSymbols::getPlatformServerName(), $doc_name, $link, $doc_link); diff -Nru phabricator-0~git20200925/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditEngine.php phabricator-0~git20220903/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -131,7 +131,7 @@ ->setKey('requireSignature') ->setOptions( pht('No Signature Required'), - pht('Signature Required to use Phabricator')) + pht('Signature Required to Log In')) ->setAsCheckbox(true) ->setTransactionType( LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE) diff -Nru phabricator-0~git20200925/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditor.php phabricator-0~git20220903/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditor.php --- phabricator-0~git20200925/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/legalpad/editor/LegalpadDocumentEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -101,7 +101,7 @@ LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE, pht('Invalid'), pht('Only documents with signature type "individual" may '. - 'require signing to use Phabricator.'), + 'require signing to log in.'), null); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/legalpad/query/LegalpadDocumentQuery.php phabricator-0~git20220903/phabricator/src/applications/legalpad/query/LegalpadDocumentQuery.php --- phabricator-0~git20200925/phabricator/src/applications/legalpad/query/LegalpadDocumentQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/legalpad/query/LegalpadDocumentQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -81,10 +81,6 @@ return new LegalpadDocument(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $documents) { if ($this->needDocumentBodies) { $documents = $this->loadDocumentBodies($documents); diff -Nru phabricator-0~git20200925/phabricator/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -53,7 +53,7 @@ } if ($map['contributorPHIDs']) { - $query->withContributorPHIDs($map['creatorPHIDs']); + $query->withContributorPHIDs($map['contributorPHIDs']); } if ($map['creatorPHIDs']) { @@ -185,8 +185,7 @@ ->setIcon($icon) ->setTitle(pht('Welcome to %s', $app_name)) ->setDescription( - pht('Create documents and track signatures. Can also be re-used in '. - 'other areas of Phabricator, like CLAs.')) + pht('Create documents and track signatures.')) ->addAction($create_button); return $view; diff -Nru phabricator-0~git20200925/phabricator/src/applications/macro/query/PhabricatorMacroQuery.php phabricator-0~git20220903/phabricator/src/applications/macro/query/PhabricatorMacroQuery.php --- phabricator-0~git20200925/phabricator/src/applications/macro/query/PhabricatorMacroQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/macro/query/PhabricatorMacroQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -100,10 +100,6 @@ return new PhabricatorFileImageMacro(); } - protected function loadPage() { - return $this->loadStandardPage(new PhabricatorFileImageMacro()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); @@ -128,7 +124,7 @@ $this->authorPHIDs); } - if (strlen($this->nameLike)) { + if (($this->nameLike !== null) && strlen($this->nameLike)) { $where[] = qsprintf( $conn, 'm.name LIKE %~', @@ -142,7 +138,7 @@ $this->names); } - if (strlen($this->namePrefix)) { + if (($this->namePrefix !== null) && strlen($this->namePrefix)) { $where[] = qsprintf( $conn, 'm.name LIKE %>', diff -Nru phabricator-0~git20200925/phabricator/src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php phabricator-0~git20220903/phabricator/src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,32 +13,14 @@ $object->setAudioPHID($value); } - public function applyExternalEffects($object, $value) { - $old = $this->generateOldValue($object); - $new = $value; - $all = array(); - if ($old) { - $all[] = $old; - } - if ($new) { - $all[] = $new; - } + public function extractFilePHIDs($object, $value) { + $file_phids = array(); - $files = id(new PhabricatorFileQuery()) - ->setViewer($this->getActor()) - ->withPHIDs($all) - ->execute(); - $files = mpull($files, null, 'getPHID'); - - $old_file = idx($files, $old); - if ($old_file) { - $old_file->detachFromObject($object->getPHID()); + if ($value) { + $file_phids[] = $value; } - $new_file = idx($files, $new); - if ($new_file) { - $new_file->attachToObject($object->getPHID()); - } + return $file_phids; } public function getTitle() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php phabricator-0~git20220903/phabricator/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,32 +13,8 @@ $object->setFilePHID($value); } - public function applyExternalEffects($object, $value) { - $old = $this->generateOldValue($object); - $new = $value; - $all = array(); - if ($old) { - $all[] = $old; - } - if ($new) { - $all[] = $new; - } - - $files = id(new PhabricatorFileQuery()) - ->setViewer($this->getActor()) - ->withPHIDs($all) - ->execute(); - $files = mpull($files, null, 'getPHID'); - - $old_file = idx($files, $old); - if ($old_file) { - $old_file->detachFromObject($object->getPHID()); - } - - $new_file = idx($files, $new); - if ($new_file) { - $new_file->attachToObject($object->getPHID()); - } + public function extractFilePHIDs($object, $value) { + return array($value); } public function getTitle() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -218,7 +218,7 @@ Statuses will appear in the UI in the order specified. Note the status marked `special` as `duplicate` is not settable directly and will not appear in UI -elements, and that any status marked `silly` does not appear if Phabricator +elements, and that any status marked `silly` does not appear if the software is configured with `phabricator.serious-business` set to true. Examining the default configuration and examples below will probably be helpful diff -Nru phabricator-0~git20200925/phabricator/src/applications/maniphest/controller/ManiphestTaskDetailController.php phabricator-0~git20220903/phabricator/src/applications/maniphest/controller/ManiphestTaskDetailController.php --- phabricator-0~git20200925/phabricator/src/applications/maniphest/controller/ManiphestTaskDetailController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/maniphest/controller/ManiphestTaskDetailController.php 2022-06-14 16:29:55.000000000 +0000 @@ -638,7 +638,9 @@ 'href' => $commit->getURI(), 'sigil' => 'hovercard', 'meta' => array( - 'hoverPHID' => $commit->getPHID(), + 'hovercardSpec' => array( + 'objectPHID' => $commit->getPHID(), + ), ), ), $commit->getSummary()); @@ -705,7 +707,9 @@ 'href' => $revision->getURI(), 'sigil' => 'hovercard', 'meta' => array( - 'hoverPHID' => $revision->getPHID(), + 'hovercardSpec' => array( + 'objectPHID' => $revision->getPHID(), + ), ), ), $revision->getTitle()); diff -Nru phabricator-0~git20200925/phabricator/src/applications/maniphest/storage/ManiphestTask.php phabricator-0~git20220903/phabricator/src/applications/maniphest/storage/ManiphestTask.php --- phabricator-0~git20200925/phabricator/src/applications/maniphest/storage/ManiphestTask.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/maniphest/storage/ManiphestTask.php 2022-06-14 16:29:55.000000000 +0000 @@ -24,8 +24,6 @@ PhabricatorPolicyCodexInterface, PhabricatorUnlockableInterface { - const MARKUP_FIELD_DESCRIPTION = 'markup:desc'; - protected $authorPHID; protected $ownerPHID; diff -Nru phabricator-0~git20200925/phabricator/src/applications/maniphest/xaction/ManiphestTaskOwnerTransaction.php phabricator-0~git20220903/phabricator/src/applications/maniphest/xaction/ManiphestTaskOwnerTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/maniphest/xaction/ManiphestTaskOwnerTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/maniphest/xaction/ManiphestTaskOwnerTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -112,7 +112,8 @@ foreach ($xactions as $xaction) { $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); - if (!strlen($new)) { + + if (!phutil_nonempty_string($new)) { continue; } @@ -127,8 +128,7 @@ if (!$assignee_list) { $errors[] = $this->newInvalidError( - pht('User "%s" is not a valid user.', - $new)); + pht('User "%s" is not a valid user.', $new)); } } return $errors; diff -Nru phabricator-0~git20200925/phabricator/src/applications/meta/controller/PhabricatorApplicationEmailCommandsController.php phabricator-0~git20220903/phabricator/src/applications/meta/controller/PhabricatorApplicationEmailCommandsController.php --- phabricator-0~git20200925/phabricator/src/applications/meta/controller/PhabricatorApplicationEmailCommandsController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/meta/controller/PhabricatorApplicationEmailCommandsController.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,12 +35,12 @@ $content[] = '= '.pht('Mail Commands Overview'); $content[] = pht( - 'After configuring Phabricator to process inbound mail, you can '. + 'After configuring processing for inbound mail, you can '. 'interact with objects (like tasks and revisions) over email. For '. - 'information on configuring Phabricator, see '. + 'information on configuring inbound mail, see '. '**[[ %s | Configuring Inbound Email ]]**.'. "\n\n". - 'In most cases, you can reply to email you receive from Phabricator '. + 'In most cases, you can reply to email you receive from this server '. 'to leave comments. You can also use **mail commands** to take a '. 'greater range of actions (like claiming a task or requesting changes '. 'to a revision) without needing to log in to the web UI.'. @@ -52,12 +52,13 @@ 'or end of your mail message. For example, you could write this in a '. 'reply to task email to claim the task:'. "\n\n```\n!claim\n\nI'll take care of this.\n```\n\n\n". - "When Phabricator receives your mail, it will process any commands ". + "When %s receives your mail, it will process any commands ". "first, then post the remaining message body as a comment. You can ". "execute multiple commands at once:". "\n\n```\n!assign alincoln\n!close\n\nI just talked to @alincoln, ". "and he showed me that he fixed this.\n```\n", - PhabricatorEnv::getDoclink('Configuring Inbound Email')); + PhabricatorEnv::getDoclink('Configuring Inbound Email'), + PlatformSymbols::getPlatformServerName()); $content[] = '= '.$spec['header']; $content[] = $spec['summary']; @@ -122,7 +123,7 @@ $info_view = null; if (!PhabricatorEnv::getEnvConfig('metamta.reply-handler-domain')) { $error = pht( - "Phabricator is not currently configured to accept inbound mail. ". + "This server is not currently configured to accept inbound mail. ". "You won't be able to interact with objects over email until ". "inbound mail is set up."); $info_view = id(new PHUIInfoView()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/meta/controller/PhabricatorApplicationUninstallController.php phabricator-0~git20220903/phabricator/src/applications/meta/controller/PhabricatorApplicationUninstallController.php --- phabricator-0~git20200925/phabricator/src/applications/meta/controller/PhabricatorApplicationUninstallController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/meta/controller/PhabricatorApplicationUninstallController.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,7 +38,7 @@ ->appendChild( pht( 'To manage prototypes, enable them by setting %s in your '. - 'Phabricator configuration.', + 'configuration.', phutil_tag('tt', array(), 'phabricator.show-prototypes'))); return id(new AphrontDialogResponse())->setDialog($dialog); } @@ -98,9 +98,9 @@ ->appendParagraph( pht( 'This is very unusual and will leave you without any '. - 'content on the Phabricator home page. You should only '. - 'do this if you are certain you know what you are doing.')) - ->addSubmitButton(pht('Completely Break Phabricator')); + 'content on the home page. You should only do this if you '. + 'are certain you know what you are doing.')) + ->addSubmitButton(pht('Completely Break Everything')); } else { $dialog ->appendParagraph( @@ -114,8 +114,7 @@ ->setTitle(pht('Information')) ->appendChild( pht( - 'This application cannot be uninstalled, '. - 'because it is required for Phabricator to work.')); + 'This application is required and cannot be uninstalled.')); } } return id(new AphrontDialogResponse())->setDialog($dialog); diff -Nru phabricator-0~git20200925/phabricator/src/applications/meta/query/PhabricatorApplicationQuery.php phabricator-0~git20220903/phabricator/src/applications/meta/query/PhabricatorApplicationQuery.php --- phabricator-0~git20200925/phabricator/src/applications/meta/query/PhabricatorApplicationQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/meta/query/PhabricatorApplicationQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -89,7 +89,7 @@ } } - if (strlen($this->nameContains)) { + if ($this->nameContains !== null) { foreach ($apps as $key => $app) { if (stripos($app->getName(), $this->nameContains) === false) { unset($apps[$key]); diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/adapter/PhabricatorMailPostmarkAdapter.php phabricator-0~git20220903/phabricator/src/applications/metamta/adapter/PhabricatorMailPostmarkAdapter.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/adapter/PhabricatorMailPostmarkAdapter.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/adapter/PhabricatorMailPostmarkAdapter.php 2022-06-14 16:29:55.000000000 +0000 @@ -33,10 +33,11 @@ // // "Configuring Outbound Email" should be updated if this changes. // - // These addresses were last updated in January 2019. + // These addresses were last updated in December 2021. '50.31.156.6/32', '50.31.156.77/32', '18.217.206.57/32', + '3.134.147.250/32', ), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/adapter/PhabricatorMailTestAdapter.php phabricator-0~git20220903/phabricator/src/applications/metamta/adapter/PhabricatorMailTestAdapter.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/adapter/PhabricatorMailTestAdapter.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/adapter/PhabricatorMailTestAdapter.php 2022-06-14 16:29:55.000000000 +0000 @@ -126,12 +126,12 @@ $guts['headers'] = $header_list; $text_body = $message->getTextBody(); - if (strlen($text_body)) { + if (phutil_nonempty_string($text_body)) { $guts['body'] = $text_body; } $html_body = $message->getHTMLBody(); - if (strlen($html_body)) { + if (phutil_nonempty_string($html_body)) { $guts['html-body'] = $html_body; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php phabricator-0~git20220903/phabricator/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -264,7 +264,7 @@ pht( 'Used if the "From:" address does not map to a user account. '. 'Setting a default author will allow anyone on the public '. - 'internet to create objects in Phabricator by sending email to '. + 'internet to create objects by sending email to '. 'this address.'))); if ($is_new) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php phabricator-0~git20220903/phabricator/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/constants/MetaMTAReceivedMailStatus.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ public static function getHumanReadableName($status) { $map = array( self::STATUS_DUPLICATE => pht('Duplicate Message'), - self::STATUS_FROM_PHABRICATOR => pht('Phabricator Mail'), + self::STATUS_FROM_PHABRICATOR => pht('Mail From Self'), self::STATUS_NO_RECEIVERS => pht('No Receivers'), self::STATUS_UNKNOWN_SENDER => pht('Unknown Sender'), self::STATUS_DISABLED_SENDER => pht('Disabled Sender'), diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php phabricator-0~git20220903/phabricator/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -119,7 +119,9 @@ if ($mail->getFrom()) { $from_str = $viewer->renderHandle($mail->getFrom()); } else { - $from_str = pht('Sent by Phabricator'); + $from_str = pht( + 'Sent by %s', + PlatformSymbols::getPlatformServerName()); } $properties->addProperty( pht('From'), @@ -428,7 +430,7 @@ if ($actor_phid) { $actor_str = $viewer->renderHandle($actor_phid); } else { - $actor_str = pht('Generated by Phabricator'); + $actor_str = pht('Generated by Server'); } $properties->addProperty(pht('Actor'), $actor_str); diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/engine/PhabricatorMailEmailEngine.php phabricator-0~git20220903/phabricator/src/applications/metamta/engine/PhabricatorMailEmailEngine.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/engine/PhabricatorMailEmailEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/engine/PhabricatorMailEmailEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -119,6 +119,8 @@ } $body_limit = PhabricatorEnv::getEnvConfig('metamta.email-body-limit'); + + $body = phutil_string_cast($body); if (strlen($body) > $body_limit) { $body = id(new PhutilUTF8StringTruncator()) ->setMaximumBytes($body_limit) @@ -143,7 +145,7 @@ if ($send_html) { $html_body = $mail->getHTMLBody(); - if (strlen($html_body)) { + if (phutil_nonempty_string($html_body)) { // NOTE: We just drop the entire HTML body if it won't fit. Safely // truncating HTML is hard, and we already have the text body to fall // back to. @@ -166,7 +168,7 @@ if (PhabricatorEnv::getEnvConfig('phabricator.silent')) { $mail->setMessage( pht( - 'Phabricator is running in silent mode. See `%s` '. + 'This software is running in silent mode. See `%s` '. 'in the configuration to change this setting.', 'phabricator.silent')); @@ -226,7 +228,7 @@ $mail = $this->getMail(); $reply_raw = $mail->getReplyTo(); - if (!strlen($reply_raw)) { + if (!phutil_nonempty_string($reply_raw)) { return null; } @@ -241,7 +243,7 @@ // If we don't have a display name, fill in a default. if (!strlen($reply_address->getDisplayName())) { - $reply_address->setDisplayName(pht('Phabricator')); + $reply_address->setDisplayName(PlatformSymbols::getPlatformServerName()); } return $reply_address; @@ -301,7 +303,11 @@ } } - $subject[] = trim($mail->getSubjectPrefix()); + $subject_prefix = $mail->getSubjectPrefix(); + $subject_prefix = phutil_string_cast($subject_prefix); + $subject_prefix = trim($subject_prefix); + + $subject[] = $subject_prefix; // If mail content must be encrypted, we replace the subject with // a generic one. @@ -313,7 +319,7 @@ $subject[] = $encrypt_subject; } else { $vary_prefix = $mail->getVarySubjectPrefix(); - if (strlen($vary_prefix)) { + if (phutil_nonempty_string($vary_prefix)) { if ($this->shouldVarySubject()) { $subject[] = $vary_prefix; } @@ -323,7 +329,7 @@ } foreach ($subject as $key => $part) { - if (!strlen($part)) { + if (!phutil_nonempty_string($part)) { unset($subject[$key]); } } @@ -403,7 +409,7 @@ $headers = array(); $thread_id = $mail->getThreadID(); - if (!strlen($thread_id)) { + if (!phutil_nonempty_string($thread_id)) { return $headers; } @@ -508,8 +514,8 @@ $address = new PhutilEmailAddress($raw_address); - if (!strlen($address->getDisplayName())) { - $address->setDisplayName(pht('Phabricator')); + if (!phutil_nonempty_string($address->getDisplayName())) { + $address->setDisplayName(PlatformSymbols::getPlatformServerName()); } return $address; diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php phabricator-0~git20220903/phabricator/src/applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,7 +6,7 @@ protected function didConstruct() { $this ->setName('list-inbound') - ->setSynopsis(pht('List inbound messages received by Phabricator.')) + ->setSynopsis(pht('List inbound messages.')) ->setExamples( '**list-inbound**') ->setArguments( diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/management/PhabricatorMailManagementListOutboundWorkflow.php phabricator-0~git20220903/phabricator/src/applications/metamta/management/PhabricatorMailManagementListOutboundWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/management/PhabricatorMailManagementListOutboundWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/management/PhabricatorMailManagementListOutboundWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,7 +6,7 @@ protected function didConstruct() { $this ->setName('list-outbound') - ->setSynopsis(pht('List outbound messages sent by Phabricator.')) + ->setSynopsis(pht('List outbound messages.')) ->setExamples('**list-outbound**') ->setArguments( array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php phabricator-0~git20220903/phabricator/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,7 +11,7 @@ * * Or * - * !assign epriestley + * !assign alincoln * * please, take this task I took; its hard * @@ -20,9 +20,9 @@ * commands. For example, this body above might parse as: * * array( - * 'body' => 'please, take this task I took; its hard', + * 'body' => 'please, take this task I took; it's hard', * 'commands' => array( - * array('assign', 'epriestley'), + * array('assign', 'alincoln'), * ), * ) * @@ -81,6 +81,7 @@ } private function stripQuotedText($body) { + $body = phutil_string_cast($body); // Look for "On <date>, <user> wrote:". This may be split across multiple // lines. We need to be careful not to remove all of a message like this: diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAActor.php phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAActor.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAActor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAActor.php 2022-06-14 16:29:55.000000000 +0000 @@ -143,7 +143,7 @@ 'recipient received the original email message, so we are not '. 'sending them this substantially similar message (for example, '. 'the sender used "Reply All" instead of "Reply" in response to '. - 'mail from Phabricator).'), + 'mail from this server).'), self::REASON_SELF => pht( 'This recipient is the user whose actions caused delivery of '. 'this message, but they have set preferences so they do not '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailPropertiesQuery.php phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailPropertiesQuery.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailPropertiesQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailPropertiesQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -20,10 +20,6 @@ return new PhabricatorMetaMTAMailProperties(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailQuery.php phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailQuery.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMailQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -36,10 +36,6 @@ return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); @@ -64,24 +60,6 @@ $this->actorPHIDs); } - if ($this->recipientPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'recipient.dst IN (%Ls)', - $this->recipientPHIDs); - } - - if ($this->actorPHIDs === null && $this->recipientPHIDs === null) { - $viewer = $this->getViewer(); - if (!$viewer->isOmnipotent()) { - $where[] = qsprintf( - $conn, - 'edge.dst = %s OR actorPHID = %s', - $viewer->getPHID(), - $viewer->getPHID()); - } - } - if ($this->createdMin !== null) { $where[] = qsprintf( $conn, @@ -102,24 +80,27 @@ protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { $joins = parent::buildJoinClauseParts($conn); - if ($this->actorPHIDs === null && $this->recipientPHIDs === null) { + if ($this->shouldJoinRecipients()) { $joins[] = qsprintf( $conn, - 'LEFT JOIN %T edge ON mail.phid = edge.src AND edge.type = %d', + 'JOIN %T recipient + ON mail.phid = recipient.src + AND recipient.type = %d + AND recipient.dst IN (%Ls)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, - PhabricatorMetaMTAMailHasRecipientEdgeType::EDGECONST); + PhabricatorMetaMTAMailHasRecipientEdgeType::EDGECONST, + $this->recipientPHIDs); } - if ($this->recipientPHIDs !== null) { - $joins[] = qsprintf( - $conn, - 'LEFT JOIN %T recipient '. - 'ON mail.phid = recipient.src AND recipient.type = %d', - PhabricatorEdgeConfig::TABLE_NAME_EDGE, - PhabricatorMetaMTAMailHasRecipientEdgeType::EDGECONST); + return $joins; + } + + private function shouldJoinRecipients() { + if ($this->recipientPHIDs === null) { + return false; } - return $joins; + return true; } protected function getPrimaryTableAlias() { @@ -134,4 +115,14 @@ return 'PhabricatorMetaMTAApplication'; } + protected function shouldGroupQueryResultRows() { + if ($this->shouldJoinRecipients()) { + if (count($this->recipientPHIDs) > 1) { + return true; + } + } + + return parent::shouldGroupQueryResultRows(); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -60,6 +60,16 @@ } $package_map[$package->getPHID()] = $package_owners; } + + // See T13648. We may have packages that no longer exist or can't be + // loaded (for example, because they have been destroyed). Give them + // empty entries in the map so we return a mapping for all input PHIDs. + + foreach ($package_phids as $package_phid) { + if (!isset($package_map[$package_phid])) { + $package_map[$package_phid] = array(); + } + } } $results = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php phabricator-0~git20220903/phabricator/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php 2022-06-14 16:29:55.000000000 +0000 @@ -72,10 +72,10 @@ MetaMTAReceivedMailStatus::STATUS_NO_PUBLIC_MAIL, pht( 'This mail is addressed to the public email address of an object '. - '("%s"), but public replies are not enabled on this Phabricator '. - 'install. An administrator may have recently disabled this '. - 'setting, or you may have replied to an old message. Try '. - 'replying to a more recent message instead.', + '("%s"), but public replies are not enabled on this server. An '. + 'administrator may have recently disabled this setting, or you '. + 'may have replied to an old message. Try replying to a more '. + 'recent message instead.', $pattern)); } $check_phid = $object->getPHID(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php phabricator-0~git20220903/phabricator/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php 2022-06-14 16:29:55.000000000 +0000 @@ -263,19 +263,16 @@ MetaMTAReceivedMailStatus::STATUS_UNKNOWN_SENDER, pht( 'This email was sent from an email address ("%s") that is not '. - 'associated with a Phabricator account. To interact with '. - 'Phabricator via email, add this address to your account.', + 'associated with a registered user account. To interact via '. + 'email, add this address to your account.', (string)$this->newFromAddress())); } else { throw new PhabricatorMetaMTAReceivedMailProcessingException( MetaMTAReceivedMailStatus::STATUS_NO_RECEIVERS, pht( - 'Phabricator can not process this mail because no application '. + 'This mail can not be processed because no application '. 'knows how to handle it. Check that the address you sent it to '. - 'is correct.'. - "\n\n". - '(No concrete, enabled subclass of PhabricatorMailReceiver can '. - 'accept this mail.)')); + 'is correct.')); } } } catch (PhabricatorMetaMTAReceivedMailProcessingException $ex) { @@ -348,9 +345,13 @@ private function getRawEmailAddresses($addresses) { $raw_addresses = array(); - foreach (explode(',', $addresses) as $address) { - $raw_addresses[] = $this->getRawEmailAddress($address); + + if (phutil_nonempty_string($addresses)) { + foreach (explode(',', $addresses) as $address) { + $raw_addresses[] = $this->getRawEmailAddress($address); + } } + return array_filter($raw_addresses); } @@ -436,7 +437,7 @@ $status_code, pht( 'Your message does not contain any body text or attachments, so '. - 'Phabricator can not do anything useful with it. Make sure comment '. + 'this server can not do anything useful with it. Make sure comment '. 'text appears at the top of your message: quoted replies, inline '. 'text, and signatures are discarded and ignored.')); } @@ -484,7 +485,7 @@ $headers = implode("\n", $headers); $body = pht(<<<EOBODY -Your email to Phabricator was not processed, because an error occurred while +Your email to %s was not processed, because an error occurred while trying to handle it: %s @@ -499,6 +500,7 @@ EOBODY , + PlatformSymbols::getPlatformServerName(), wordwrap($description, 78), $this->getRawTextBody(), $headers); @@ -563,21 +565,20 @@ if ($sender->getIsDisabled()) { $failure_reason = pht( 'Your account ("%s") is disabled, so you can not interact with '. - 'Phabricator over email.', + 'over email.', $sender->getUsername()); } else if ($sender->getIsStandardUser()) { if (!$sender->getIsApproved()) { $failure_reason = pht( 'Your account ("%s") has not been approved yet. You can not '. - 'interact with Phabricator over email until your account is '. - 'approved.', + 'interact over email until your account is approved.', $sender->getUsername()); } else if (PhabricatorUserEmail::isEmailVerificationRequired() && !$sender->getIsEmailVerified()) { $failure_reason = pht( 'You have not verified the email address for your account ("%s"). '. - 'You must verify your email address before you can interact '. - 'with Phabricator over email.', + 'You must verify your email address before you can interact over '. + 'email.', $sender->getUsername()); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php phabricator-0~git20220903/phabricator/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -395,7 +395,7 @@ // We expect the HTML body was dropped completely after the text body was // truncated. $this->assertTrue( - !strlen($html_body), + !phutil_nonempty_string($html_body), pht('HTML Body Removed')); @@ -416,7 +416,7 @@ $html_body = $mailer->getHTMLBody(); $this->assertEqual($string_1kb, $text_body); - $this->assertTrue(!strlen($html_body)); + $this->assertTrue(!phutil_nonempty_string($html_body)); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/metamta/util/PhabricatorMailUtil.php phabricator-0~git20220903/phabricator/src/applications/metamta/util/PhabricatorMailUtil.php --- phabricator-0~git20200925/phabricator/src/applications/metamta/util/PhabricatorMailUtil.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/metamta/util/PhabricatorMailUtil.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,11 +21,10 @@ // If a mailbox prefix is configured and present, strip it off. $prefix_key = 'metamta.single-reply-handler-prefix'; $prefix = PhabricatorEnv::getEnvConfig($prefix_key); - $len = strlen($prefix); - if ($len) { + if (phutil_nonempty_string($prefix)) { $prefix = $prefix.'+'; - $len = $len + 1; + $len = strlen($prefix); if (!strncasecmp($raw_address, $prefix, $len)) { $raw_address = substr($raw_address, $len); diff -Nru phabricator-0~git20200925/phabricator/src/applications/notification/query/PhabricatorNotificationQuery.php phabricator-0~git20220903/phabricator/src/applications/notification/query/PhabricatorNotificationQuery.php --- phabricator-0~git20200925/phabricator/src/applications/notification/query/PhabricatorNotificationQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/notification/query/PhabricatorNotificationQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -63,17 +63,7 @@ $this->buildWhereClause($conn), $this->buildLimitClause($conn)); - $viewed_map = ipull($data, 'hasViewed', 'chronologicalKey'); - - $stories = PhabricatorFeedStory::loadAllFromRows( - $data, - $this->getViewer()); - - foreach ($stories as $key => $story) { - $story->setHasViewed($viewed_map[$key]); - } - - return $stories; + return $data; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { @@ -103,14 +93,47 @@ return $where; } - protected function willFilterPage(array $stories) { - foreach ($stories as $key => $story) { + protected function willFilterPage(array $rows) { + // See T13623. The policy model here is outdated and awkward. + + // Users may have notifications about objects they can no longer see. + // Two ways this can arise: destroy an object; or change an object's + // view policy to exclude a user. + + // "PhabricatorFeedStory::loadAllFromRows()" does its own policy filtering. + // This doesn't align well with modern query sequencing, but we should be + // able to get away with it by loading here. + + // See T13623. Although most queries for notifications return unique + // stories, this isn't a guarantee. + $story_map = ipull($rows, null, 'chronologicalKey'); + + $viewer = $this->getViewer(); + $stories = PhabricatorFeedStory::loadAllFromRows($story_map, $viewer); + $stories = mpull($stories, null, 'getChronologicalKey'); + + $results = array(); + foreach ($rows as $row) { + $story_key = $row['chronologicalKey']; + $has_viewed = $row['hasViewed']; + + if (!isset($stories[$story_key])) { + // NOTE: We can't call "didRejectResult()" here because we don't have + // a policy object to pass. + continue; + } + + $story = id(clone $stories[$story_key]) + ->setHasViewed($has_viewed); + if (!$story->isVisibleInNotifications()) { - unset($stories[$key]); + continue; } + + $results[] = $story; } - return $stories; + return $results; } protected function getDefaultOrderVector() { @@ -145,7 +168,11 @@ protected function applyExternalCursorConstraintsToQuery( PhabricatorCursorPagedPolicyAwareQuery $subquery, $cursor) { - $subquery->withKeys(array($cursor)); + + $subquery + ->withKeys(array($cursor)) + ->setLimit(1); + } protected function newExternalCursorStringForResult($object) { @@ -154,7 +181,7 @@ protected function newPagingMapFromPartialObject($object) { return array( - 'key' => $object->getChronologicalKey(), + 'key' => $object['chronologicalKey'], ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php phabricator-0~git20220903/phabricator/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php --- phabricator-0~git20200925/phabricator/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,7 +7,7 @@ PhabricatorNotificationClient::tryAnyConnection(); } catch (Exception $ex) { $message = pht( - "Phabricator is configured to use a notification server, but is ". + "This server is configured to use a notification server, but is ". "unable to connect to it. You should resolve this issue or disable ". "the notification server. It may be helpful to double check your ". "configuration or restart the server using the command below.\n\n%s", @@ -26,14 +26,14 @@ ->setName(pht('Unable to Connect to Notification Server')) ->setSummary( pht( - 'Phabricator is configured to use a notification server, '. + 'This server is configured to use a notification server, '. 'but is not able to connect to it.')) ->setMessage($message) ->addRelatedPhabricatorConfig('notification.servers') ->addCommand( pht( "(To start the server, run this command.)\n%s", - 'phabricator/ $ ./bin/aphlict start')); + '$ ./bin/aphlict start')); return; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/nuance/github/NuanceGitHubRawEvent.php phabricator-0~git20220903/phabricator/src/applications/nuance/github/NuanceGitHubRawEvent.php --- phabricator-0~git20200925/phabricator/src/applications/nuance/github/NuanceGitHubRawEvent.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/nuance/github/NuanceGitHubRawEvent.php 2022-06-14 16:29:55.000000000 +0000 @@ -164,7 +164,7 @@ $raw = $this->raw; $full = idxv($raw, array('repo', 'name')); - if (strlen($full)) { + if (phutil_nonempty_string($full)) { return $full; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceImportCursorDataQuery.php phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceImportCursorDataQuery.php --- phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceImportCursorDataQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceImportCursorDataQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new NuanceImportCursorData(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceItemCommandQuery.php phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceItemCommandQuery.php --- phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceItemCommandQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceItemCommandQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new NuanceItemCommand(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceItemQuery.php phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceItemQuery.php --- phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceItemQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceItemQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -56,10 +56,6 @@ return new NuanceItem(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $items) { $viewer = $this->getViewer(); $source_phids = mpull($items, 'getSourcePHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceQueueQuery.php phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceQueueQuery.php --- phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceQueueQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceQueueQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -20,10 +20,6 @@ return new NuanceQueue(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceSourceQuery.php phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceSourceQuery.php --- phabricator-0~git20200925/phabricator/src/applications/nuance/query/NuanceSourceQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/nuance/query/NuanceSourceQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -48,10 +48,6 @@ return 'source'; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $sources) { $all_types = NuanceSourceDefinition::getAllDefinitions(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php phabricator-0~git20220903/phabricator/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php --- phabricator-0~git20200925/phabricator/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,7 +4,7 @@ extends NuanceSourceDefinition { public function getName() { - return pht('Phabricator Form'); + return pht('Web Form'); } public function getSourceDescription() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php phabricator-0~git20220903/phabricator/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php --- phabricator-0~git20200925/phabricator/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -23,7 +23,9 @@ } public function getFlavorText() { - return pht('Log In with Phabricator'); + return pht( + 'Log In with %s', + PlatformSymbols::getPlatformServerName()); } public function getApplicationGroup() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDisableController.php phabricator-0~git20220903/phabricator/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDisableController.php --- phabricator-0~git20200925/phabricator/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDisableController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDisableController.php 2022-06-14 16:29:55.000000000 +0000 @@ -43,7 +43,7 @@ $title = pht('Disable OAuth Application'); $body = pht( 'Really disable the %s OAuth application? Users will no longer be '. - 'able to authenticate against it, nor access Phabricator using '. + 'able to authenticate against it, nor access this server using '. 'tokens generated by this application.', phutil_tag('strong', array(), $client->getName())); $button = pht('Disable Application'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/oauthserver/controller/PhabricatorOAuthServerAuthController.php phabricator-0~git20220903/phabricator/src/applications/oauthserver/controller/PhabricatorOAuthServerAuthController.php --- phabricator-0~git20200925/phabricator/src/applications/oauthserver/controller/PhabricatorOAuthServerAuthController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/oauthserver/controller/PhabricatorOAuthServerAuthController.php 2022-06-14 16:29:55.000000000 +0000 @@ -209,9 +209,10 @@ ->setTitle(pht('Authenticate: %s', $name)) ->appendParagraph( pht( - 'This application ("%s") is authorized to use your Phabricator '. + 'This application ("%s") is authorized to use your %s '. 'credentials. Continue to complete the authentication workflow.', - phutil_tag('strong', array(), $name))) + phutil_tag('strong', array(), $name), + PlatformSymbols::getPlatformServerName())) ->addCancelButton((string)$full_uri, pht('Continue to Application')); return id(new AphrontDialogResponse())->setDialog($dialog); @@ -248,9 +249,10 @@ ->appendParagraph( pht( 'Do you want to authorize the external application "%s" to '. - 'access your Phabricator account data, including your primary '. + 'access your %s account data, including your primary '. 'email address?', - phutil_tag('strong', array(), $name))) + phutil_tag('strong', array(), $name), + PlatformSymbols::getPlatformServerName())) ->appendForm($form) ->addSubmitButton(pht('Authorize Access')) ->addCancelButton((string)$cancel_uri, pht('Do Not Authorize')); @@ -271,8 +273,8 @@ pht( 'This application also requested additional unrecognized '. 'permissions. These permissions may have existed in an older '. - 'version of Phabricator, or may be from a future version of '. - 'Phabricator. They will not be granted.')); + 'version of the software, or may be from a future version of '. + 'the software. They will not be granted.')); $unknown_form = id(new AphrontFormView()) ->setViewer($viewer) diff -Nru phabricator-0~git20200925/phabricator/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php phabricator-0~git20220903/phabricator/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php --- phabricator-0~git20200925/phabricator/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -68,7 +68,7 @@ ->setTitle(pht('Revoke Authorization?')) ->appendParagraph( pht( - 'This application will no longer be able to access Phabricator '. + 'This application will no longer be able to access this server '. 'on your behalf.')) ->addSubmitButton(pht('Revoke Authorization')) ->addCancelButton($panel_uri); diff -Nru phabricator-0~git20200925/phabricator/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php phabricator-0~git20220903/phabricator/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php --- phabricator-0~git20200925/phabricator/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorOAuthClientAuthorization(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $authorizations) { $client_phids = mpull($authorizations, 'getClientPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/conduit/OwnersQueryConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -<?php - -final class OwnersQueryConduitAPIMethod extends OwnersConduitAPIMethod { - - public function getAPIMethodName() { - return 'owners.query'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_DEPRECATED; - } - - public function getMethodStatusDescription() { - return pht('Obsolete; use "owners.search" instead.'); - } - - - public function getMethodDescription() { - return pht('Query for Owners packages. Obsoleted by "owners.search".'); - } - - protected function defineParamTypes() { - return array( - 'userOwner' => 'optional string', - 'projectOwner' => 'optional string', - 'userAffiliated' => 'optional string', - 'repositoryCallsign' => 'optional string', - 'path' => 'optional string', - ); - } - - protected function defineReturnType() { - return 'dict<phid -> dict of package info>'; - } - - protected function defineErrorTypes() { - return array( - 'ERR-INVALID-USAGE' => pht( - 'Provide one of a single owner phid (user/project), a single '. - 'affiliated user phid (user), or a repository/path.'), - 'ERR-INVALID-PARAMETER' => pht('Parameter should be a phid.'), - 'ERR_REP_NOT_FOUND' => pht('The repository callsign is not recognized.'), - ); - } - - protected static function queryAll() { - return id(new PhabricatorOwnersPackage())->loadAll(); - } - - protected static function queryByOwner($owner) { - $is_valid_phid = - phid_get_type($owner) == PhabricatorPeopleUserPHIDType::TYPECONST || - phid_get_type($owner) == PhabricatorProjectProjectPHIDType::TYPECONST; - - if (!$is_valid_phid) { - throw id(new ConduitException('ERR-INVALID-PARAMETER')) - ->setErrorDescription( - pht( - 'Expected user/project PHID for owner, got %s.', - $owner)); - } - - $owners = id(new PhabricatorOwnersOwner())->loadAllWhere( - 'userPHID = %s', - $owner); - - $package_ids = mpull($owners, 'getPackageID'); - $packages = array(); - foreach ($package_ids as $id) { - $packages[] = id(new PhabricatorOwnersPackage())->load($id); - } - return $packages; - } - - private static function queryByPath( - PhabricatorUser $viewer, - $repo_callsign, - $path) { - - $repository = id(new PhabricatorRepositoryQuery()) - ->setViewer($viewer) - ->withCallsigns(array($repo_callsign)) - ->executeOne(); - - if (!$repository) { - throw id(new ConduitException('ERR_REP_NOT_FOUND')) - ->setErrorDescription( - pht( - 'Repository callsign %s not recognized', - $repo_callsign)); - } - if ($path == null) { - return PhabricatorOwnersPackage::loadPackagesForRepository($repository); - } else { - return PhabricatorOwnersPackage::loadOwningPackages( - $repository, $path); - } - } - - public static function buildPackageInformationDictionaries($packages) { - assert_instances_of($packages, 'PhabricatorOwnersPackage'); - - $result = array(); - foreach ($packages as $package) { - $p_owners = $package->loadOwners(); - $p_paths = $package->loadPaths(); - - $owners = array_values(mpull($p_owners, 'getUserPHID')); - $paths = array(); - foreach ($p_paths as $p) { - $paths[] = array($p->getRepositoryPHID(), $p->getPath()); - } - - $result[$package->getPHID()] = array( - 'phid' => $package->getPHID(), - 'name' => $package->getName(), - 'description' => $package->getDescription(), - 'owners' => $owners, - 'paths' => $paths, - ); - } - return $result; - } - - protected function execute(ConduitAPIRequest $request) { - $is_owner_query = - ($request->getValue('userOwner') || - $request->getValue('projectOwner')) ? - 1 : 0; - - $is_affiliated_query = $request->getValue('userAffiliated') ? 1 : 0; - - $repo = $request->getValue('repositoryCallsign'); - $path = $request->getValue('path'); - $is_path_query = $repo ? 1 : 0; - - if ($is_owner_query + $is_path_query + $is_affiliated_query === 0) { - // if no search terms are provided, return everything - $packages = self::queryAll(); - } else if ($is_owner_query + $is_path_query + $is_affiliated_query > 1) { - // otherwise, exactly one of these should be provided - throw new ConduitException('ERR-INVALID-USAGE'); - } - - if ($is_affiliated_query) { - $query = id(new PhabricatorOwnersPackageQuery()) - ->setViewer($request->getUser()); - - $query->withAuthorityPHIDs(array($request->getValue('userAffiliated'))); - - $packages = $query->execute(); - } else if ($is_owner_query) { - $owner = nonempty( - $request->getValue('userOwner'), - $request->getValue('projectOwner')); - - $packages = self::queryByOwner($owner); - - } else if ($is_path_query) { - $packages = self::queryByPath($request->getUser(), $repo, $path); - } - - return self::buildPackageInformationDictionaries($packages); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/controller/PhabricatorOwnersDetailController.php phabricator-0~git20220903/phabricator/src/applications/owners/controller/PhabricatorOwnersDetailController.php --- phabricator-0~git20200925/phabricator/src/applications/owners/controller/PhabricatorOwnersDetailController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/controller/PhabricatorOwnersDetailController.php 2022-06-14 16:29:55.000000000 +0000 @@ -197,6 +197,12 @@ $name = idx($spec, 'short', $dominion); $view->addProperty(pht('Dominion'), $name); + $authority_mode = $package->getAuthorityMode(); + $authority_map = PhabricatorOwnersPackage::getAuthorityOptionsMap(); + $spec = idx($authority_map, $authority_mode, array()); + $name = idx($spec, 'short', $authority_mode); + $view->addProperty(pht('Authority'), $name); + $auto = $package->getAutoReview(); $autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap(); $spec = idx($autoreview_map, $auto, array()); diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php phabricator-0~git20220903/phabricator/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -90,6 +90,9 @@ $dominion_map = PhabricatorOwnersPackage::getDominionOptionsMap(); $dominion_map = ipull($dominion_map, 'name'); + $authority_map = PhabricatorOwnersPackage::getAuthorityOptionsMap(); + $authority_map = ipull($authority_map, 'name'); + return array( id(new PhabricatorTextEditField()) ->setKey('name') @@ -119,6 +122,16 @@ ->setValue($object->getDominion()) ->setOptions($dominion_map), id(new PhabricatorSelectEditField()) + ->setKey('authority') + ->setLabel(pht('Authority')) + ->setDescription( + pht('Change package authority rules.')) + ->setTransactionType( + PhabricatorOwnersPackageAuthorityTransaction::TRANSACTIONTYPE) + ->setIsCopyable(true) + ->setValue($object->getAuthorityMode()) + ->setOptions($authority_map), + id(new PhabricatorSelectEditField()) ->setKey('autoReview') ->setLabel(pht('Auto Review')) ->setDescription( diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/query/PhabricatorOwnersPackageQuery.php phabricator-0~git20220903/phabricator/src/applications/owners/query/PhabricatorOwnersPackageQuery.php --- phabricator-0~git20200925/phabricator/src/applications/owners/query/PhabricatorOwnersPackageQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/query/PhabricatorOwnersPackageQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,6 +10,7 @@ private $repositoryPHIDs; private $paths; private $statuses; + private $authorityModes; private $controlMap = array(); private $controlResults; @@ -77,6 +78,11 @@ return $this; } + public function withAuthorityModes(array $modes) { + $this->authorityModes = $modes; + return $this; + } + public function withNameNgrams($ngrams) { return $this->withNgramsConstraint( new PhabricatorOwnersPackageNameNgrams(), @@ -96,10 +102,6 @@ $this->controlResults = array(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $packages) { $package_ids = mpull($packages, 'getID'); @@ -231,6 +233,13 @@ $where[] = qsprintf($conn, '%LO', $clauses); } + if ($this->authorityModes !== null) { + $where[] = qsprintf( + $conn, + 'authorityMode IN (%Ls)', + $this->authorityModes); + } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -168,8 +168,9 @@ ->setIcon($icon) ->setTitle(pht('Welcome to %s', $app_name)) ->setDescription( - pht('Group sections of a codebase into packages for re-use in other '. - 'areas of Phabricator, like Herald rules.')) + pht( + 'Group sections of a codebase into packages for re-use in other '. + 'applications, like Herald rules.')) ->addAction($create_button); return $view; diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/storage/PhabricatorOwnersPackage.php phabricator-0~git20220903/phabricator/src/applications/owners/storage/PhabricatorOwnersPackage.php --- phabricator-0~git20200925/phabricator/src/applications/owners/storage/PhabricatorOwnersPackage.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/storage/PhabricatorOwnersPackage.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,6 +21,7 @@ protected $dominion; protected $properties = array(); protected $auditingState; + protected $authorityMode; private $paths = self::ATTACHABLE; private $owners = self::ATTACHABLE; @@ -41,6 +42,9 @@ const DOMINION_STRONG = 'strong'; const DOMINION_WEAK = 'weak'; + const AUTHORITY_STRONG = 'strong'; + const AUTHORITY_WEAK = 'weak'; + const PROPERTY_IGNORED = 'ignored'; public static function initializeNewPackage(PhabricatorUser $actor) { @@ -58,6 +62,7 @@ ->setAuditingState(PhabricatorOwnersAuditRule::AUDITING_NONE) ->setAutoReview(self::AUTOREVIEW_NONE) ->setDominion(self::DOMINION_STRONG) + ->setAuthorityMode(self::AUTHORITY_STRONG) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->attachPaths(array()) @@ -115,6 +120,19 @@ ); } + public static function getAuthorityOptionsMap() { + return array( + self::AUTHORITY_STRONG => array( + 'name' => pht('Strong (Package Owns Paths)'), + 'short' => pht('Strong'), + ), + self::AUTHORITY_WEAK => array( + 'name' => pht('Weak (Package Watches Paths)'), + 'short' => pht('Weak'), + ), + ); + } + protected function getConfiguration() { return array( // This information is better available from the history table. @@ -130,6 +148,7 @@ 'status' => 'text32', 'autoReview' => 'text32', 'dominion' => 'text32', + 'authorityMode' => 'text32', ), ) + parent::getConfiguration(); } @@ -568,6 +587,10 @@ return PhabricatorOwnersAuditRule::newFromState($this->getAuditingState()); } + public function getHasStrongAuthority() { + return ($this->getAuthorityMode() === self::AUTHORITY_STRONG); + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ @@ -697,6 +720,10 @@ ->setType('map<string, wild>') ->setDescription(pht('Dominion setting information.')), id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('authority') + ->setType('map<string, wild>') + ->setDescription(pht('Authority setting information.')), + id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('ignored') ->setType('map<string, wild>') ->setDescription(pht('Ignored attribute information.')), @@ -747,6 +774,23 @@ 'short' => $dominion_short, ); + + $authority_value = $this->getAuthorityMode(); + $authority_map = self::getAuthorityOptionsMap(); + if (isset($authority_map[$authority_value])) { + $authority_label = $authority_map[$authority_value]['name']; + $authority_short = $authority_map[$authority_value]['short']; + } else { + $authority_label = pht('Unknown ("%s")', $authority_value); + $authority_short = pht('Unknown ("%s")', $authority_value); + } + + $authority = array( + 'value' => $authority_value, + 'label' => $authority_label, + 'short' => $authority_short, + ); + // Force this to always emit as a JSON object even if empty, never as // a JSON list. $ignored = $this->getIgnoredPathAttributes(); @@ -762,6 +806,7 @@ 'review' => $review, 'audit' => $audit, 'dominion' => $dominion, + 'authority' => $authority, 'ignored' => $ignored, ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php phabricator-0~git20220903/phabricator/src/applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -14,34 +14,34 @@ 'id' => 1, 'excluded' => 1, 'dominion' => PhabricatorOwnersPackage::DOMINION_STRONG, - 'path' => 'src/releeph/', + 'path' => 'src/example/', ), array( 'id' => 2, 'excluded' => 0, 'dominion' => PhabricatorOwnersPackage::DOMINION_STRONG, - 'path' => 'src/releeph/', + 'path' => 'src/example/', ), ); $paths = array( - 'src/' => array('src/a.php' => true, 'src/releeph/b.php' => true), - 'src/releeph/' => array('src/releeph/b.php' => true), + 'src/' => array('src/a.php' => true, 'src/example/b.php' => true), + 'src/example/' => array('src/example/b.php' => true), ); $this->assertEqual( array( 1 => strlen('src/'), - 2 => strlen('src/releeph/'), + 2 => strlen('src/example/'), ), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); $paths = array( - 'src/' => array('src/releeph/b.php' => true), - 'src/releeph/' => array('src/releeph/b.php' => true), + 'src/' => array('src/example/b.php' => true), + 'src/example/' => array('src/example/b.php' => true), ); $this->assertEqual( array( - 2 => strlen('src/releeph/'), + 2 => strlen('src/example/'), ), PhabricatorOwnersPackage::findLongestPathsPerPackage($rows, $paths)); diff -Nru phabricator-0~git20200925/phabricator/src/applications/owners/xaction/PhabricatorOwnersPackageAuthorityTransaction.php phabricator-0~git20220903/phabricator/src/applications/owners/xaction/PhabricatorOwnersPackageAuthorityTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/owners/xaction/PhabricatorOwnersPackageAuthorityTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/owners/xaction/PhabricatorOwnersPackageAuthorityTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,56 @@ +<?php + +final class PhabricatorOwnersPackageAuthorityTransaction + extends PhabricatorOwnersPackageTransactionType { + + const TRANSACTIONTYPE = 'owners.authority'; + + public function generateOldValue($object) { + return $object->getAuthorityMode(); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $map = PhabricatorOwnersPackage::getAuthorityOptionsMap(); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + + if (empty($map[$new])) { + $valid = array_keys($map); + + $errors[] = $this->newInvalidError( + pht( + 'Authority setting "%s" is not valid. '. + 'Valid settings are: %s.', + $new, + implode(', ', $valid)), + $xaction); + } + } + + return $errors; + } + + public function applyInternalEffects($object, $value) { + $object->setAuthorityMode($value); + } + + public function getTitle() { + $map = PhabricatorOwnersPackage::getAuthorityOptionsMap(); + $map = ipull($map, 'short'); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $old = idx($map, $old, $old); + $new = idx($map, $new, $new); + + return pht( + '%s adjusted package authority rules from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old), + $this->renderValue($new)); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/packages/application/PhabricatorPackagesApplication.php phabricator-0~git20220903/phabricator/src/applications/packages/application/PhabricatorPackagesApplication.php --- phabricator-0~git20200925/phabricator/src/applications/packages/application/PhabricatorPackagesApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/packages/application/PhabricatorPackagesApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,7 +15,7 @@ } public function getBaseURI() { - return '/packages/'; + return '/packages/package/'; } public function getIcon() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/packages/query/PhabricatorPackagesPackageQuery.php phabricator-0~git20220903/phabricator/src/applications/packages/query/PhabricatorPackagesPackageQuery.php --- phabricator-0~git20200925/phabricator/src/applications/packages/query/PhabricatorPackagesPackageQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/packages/query/PhabricatorPackagesPackageQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,10 +44,6 @@ return new PhabricatorPackagesPackage(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/packages/query/PhabricatorPackagesPublisherQuery.php phabricator-0~git20220903/phabricator/src/applications/packages/query/PhabricatorPackagesPublisherQuery.php --- phabricator-0~git20200925/phabricator/src/applications/packages/query/PhabricatorPackagesPublisherQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/packages/query/PhabricatorPackagesPublisherQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhabricatorPackagesPublisher(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/packages/query/PhabricatorPackagesVersionQuery.php phabricator-0~git20220903/phabricator/src/applications/packages/query/PhabricatorPackagesVersionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/packages/query/PhabricatorPackagesVersionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/packages/query/PhabricatorPackagesVersionQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,10 +44,6 @@ return new PhabricatorPackagesVersion(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/passphrase/query/PassphraseCredentialQuery.php phabricator-0~git20220903/phabricator/src/applications/passphrase/query/PassphraseCredentialQuery.php --- phabricator-0~git20200925/phabricator/src/applications/passphrase/query/PassphraseCredentialQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/passphrase/query/PassphraseCredentialQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -57,10 +57,6 @@ return new PassphraseCredential(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { if ($this->needSecrets) { $secret_ids = mpull($page, 'getSecretID'); @@ -148,7 +144,7 @@ (int)$this->allowConduit); } - if (strlen($this->nameContains)) { + if (phutil_nonempty_string($this->nameContains)) { $where[] = qsprintf( $conn, 'LOWER(c.name) LIKE %~', diff -Nru phabricator-0~git20200925/phabricator/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -124,8 +124,7 @@ ->setIcon($icon) ->setTitle(pht('Welcome to %s', $app_name)) ->setDescription( - pht('Credential management for re-use in other areas of Phabricator '. - 'or general storage of shared secrets.')) + pht('Credential management and general storage of shared secrets.')) ->addAction($create_button); return $view; diff -Nru phabricator-0~git20200925/phabricator/src/applications/paste/query/PhabricatorPasteQuery.php phabricator-0~git20220903/phabricator/src/applications/paste/query/PhabricatorPasteQuery.php --- phabricator-0~git20200925/phabricator/src/applications/paste/query/PhabricatorPasteQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/paste/query/PhabricatorPasteQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -84,10 +84,6 @@ return new PhabricatorPaste(); } - protected function loadPage() { - return $this->loadStandardPage(new PhabricatorPaste()); - } - protected function didFilterPage(array $pastes) { if ($this->needRawContent) { $pastes = $this->loadRawContent($pastes); diff -Nru phabricator-0~git20200925/phabricator/src/applications/paste/xaction/PhabricatorPasteContentTransaction.php phabricator-0~git20220903/phabricator/src/applications/paste/xaction/PhabricatorPasteContentTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/paste/xaction/PhabricatorPasteContentTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/paste/xaction/PhabricatorPasteContentTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -5,6 +5,8 @@ const TRANSACTIONTYPE = 'paste.create'; + private $filePHID; + public function generateOldValue($object) { return $object->getFilePHID(); } @@ -14,7 +16,8 @@ } public function extractFilePHIDs($object, $value) { - return array($value); + $file_phid = $this->getFilePHID($object, $value); + return array($file_phid); } public function validateTransactions($object, array $xactions) { @@ -31,6 +34,18 @@ } public function generateNewValue($object, $value) { + return $this->getFilePHID($object, $value); + } + + private function getFilePHID($object, $value) { + if ($this->filePHID === null) { + $this->filePHID = $this->newFilePHID($object, $value); + } + + return $this->filePHID; + } + + private function newFilePHID($object, $value) { // If this transaction does not really change the paste content, return // the current file PHID so this transaction no-ops. $old_content = $object->getRawContent(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleApproveController.php phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleApproveController.php --- phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleApproveController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleApproveController.php 2022-06-14 16:29:55.000000000 +0000 @@ -52,7 +52,7 @@ ->setTitle(pht('Confirm Approval')) ->appendChild( pht( - 'Allow %s to access this Phabricator install?', + 'Allow %s to access this server?', phutil_tag('strong', array(), $user->getUsername()))) ->addCancelButton($done_uri) ->addSubmitButton(pht('Approve Account')); diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleCreateController.php phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleCreateController.php --- phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleCreateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleCreateController.php 2022-06-14 16:29:55.000000000 +0000 @@ -24,7 +24,7 @@ $title = pht('Create New User'); $standard_caption = pht( - 'Create a standard user account. These users can log in to Phabricator, '. + 'Create a standard user account. These users can log in, '. 'use the web interface and API, and receive email.'); $standard_admin = pht( diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleDisableController.php phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleDisableController.php --- phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleDisableController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleDisableController.php 2022-06-14 16:29:55.000000000 +0000 @@ -90,7 +90,7 @@ $short_title = pht('Disable User'); $body = pht( - 'Disable %s? They will no longer be able to access Phabricator or '. + 'Disable %s? They will no longer be able to access this server or '. 'receive email.', phutil_tag('strong', array(), $user->getUsername())); @@ -100,7 +100,7 @@ $short_title = pht('Enable User'); $body = pht( - 'Enable %s? They will be able to access Phabricator and receive '. + 'Enable %s? They will be able to access this server and receive '. 'email again.', phutil_tag('strong', array(), $user->getUsername())); diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleEmpowerController.php phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleEmpowerController.php --- phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleEmpowerController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleEmpowerController.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,7 +44,7 @@ $short = pht('Remove Administrator'); $body = pht( 'Remove %s as an administrator? They will no longer be able to '. - 'perform administrative functions on this Phabricator install.', + 'perform administrative functions on this server.', phutil_tag('strong', array(), $user->getUsername())); $submit = pht('Remove Administrator'); } else { @@ -53,7 +53,7 @@ $body = pht( 'Empower %s as an administrator? They will be able to create users, '. 'approve users, make and remove administrators, delete accounts, and '. - 'perform other administrative functions on this Phabricator install.', + 'perform other administrative functions on this server.', phutil_tag('strong', array(), $user->getUsername())); $submit = pht('Make Administrator'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleInviteSendController.php phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleInviteSendController.php --- phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleInviteSendController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleInviteSendController.php 2022-06-14 16:29:55.000000000 +0000 @@ -77,8 +77,9 @@ $template = array(); $template[] = pht( - '%s has invited you to join Phabricator.', - $viewer->getFullName()); + '%s has invited you to join %s.', + $viewer->getFullName(), + PlatformSymbols::getPlatformServerName()); if (strlen(trim($message))) { $template[] = $message; @@ -174,7 +175,7 @@ ->setUser($viewer) ->appendRemarkupInstructions( pht( - 'To invite users to Phabricator, enter their email addresses below. '. + 'To invite users, enter their email addresses below. '. 'Separate addresses with commas or newlines.')) ->appendChild( id(new AphrontFormTextAreaControl()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleNewController.php phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleNewController.php --- phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleNewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleNewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -185,7 +185,9 @@ ->addCheckbox( 'welcome', 1, - pht('Send "Welcome to Phabricator" email with login instructions.'), + pht( + 'Send "Welcome to %s" email with login instructions.', + PlatformSymbols::getPlatformServerName()), $welcome_checked)); } @@ -202,15 +204,15 @@ pht( '**Why do bot accounts need an email address?**'. "\n\n". - 'Although bots do not normally receive email from Phabricator, '. - 'they can interact with other systems which require an email '. - 'address. Examples include:'. + 'Although bots do not normally receive email, they can interact '. + 'with other systems which require an email address. Examples '. + 'include:'. "\n\n". " - If the account takes actions which //send// email, we need ". " an address to use in the //From// header.\n". " - If the account creates commits, Git and Mercurial require ". " an email address for authorship.\n". - " - If you send email //to// Phabricator on behalf of the ". + " - If you send email //to// this server on behalf of the ". " account, the address can identify the sender.\n". " - Some internal authentication functions depend on accounts ". " having an email address.\n". diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleWelcomeController.php phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleWelcomeController.php --- phabricator-0~git20200925/phabricator/src/applications/people/controller/PhabricatorPeopleWelcomeController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/controller/PhabricatorPeopleWelcomeController.php 2022-06-14 16:29:55.000000000 +0000 @@ -68,9 +68,10 @@ ->appendRemarkupInstructions( pht( 'This workflow will send this user ("%s") a copy of the "Welcome to '. - 'Phabricator" email that users normally receive when their '. + '%s" email that users normally receive when their '. 'accounts are created by an administrator.', - $user->getUsername())) + $user->getUsername(), + PlatformSymbols::getPlatformServerName())) ->appendRemarkupInstructions( pht( 'The email will contain a link that the user may use to log in '. diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/engineextension/PeopleHovercardEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/people/engineextension/PeopleHovercardEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/people/engineextension/PeopleHovercardEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/engineextension/PeopleHovercardEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -47,12 +47,14 @@ return; } + $is_exiled = $hovercard->getIsExiled(); + $user_card = id(new PhabricatorUserCardView()) ->setProfile($user) - ->setViewer($viewer); + ->setViewer($viewer) + ->setIsExiled($is_exiled); $hovercard->appendChild($user_card); - } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php phabricator-0~git20220903/phabricator/src/applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php --- phabricator-0~git20200925/phabricator/src/applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -28,9 +28,13 @@ $is_set_password = $this->isSetPasswordWorkflow(); if ($is_set_password) { - $subject = pht('[Phabricator] Account Password Link'); + $subject = pht( + '[%s] Account Password Link', + PlatformSymbols::getPlatformServerName()); } else { - $subject = pht('[Phabricator] Account Login Link'); + $subject = pht( + '[%s] Account Login Link', + PlatformSymbols::getPlatformServerName()); } $recipient = $this->getRecipient(); @@ -72,7 +76,7 @@ $login_uri); } else if ($is_serious) { $body[] = pht( - "You can use this link to reset your Phabricator password:". + "You can use this link to reset your password:". "\n\n %s\n", $login_uri); } else { @@ -90,8 +94,7 @@ } } else { $body[] = pht( - "You can use this login link to regain access to your Phabricator ". - "account:". + "You can use this login link to regain access to your account:". "\n\n". " %s\n", $login_uri); diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/mail/PhabricatorPeopleUsernameMailEngine.php phabricator-0~git20220903/phabricator/src/applications/people/mail/PhabricatorPeopleUsernameMailEngine.php --- phabricator-0~git20200925/phabricator/src/applications/people/mail/PhabricatorPeopleUsernameMailEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/mail/PhabricatorPeopleUsernameMailEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,9 +40,10 @@ $body = sprintf( "%s\n\n %s\n %s\n", pht( - '%s (%s) has changed your Phabricator username.', + '%s (%s) has changed your %s username.', $sender_username, - $sender_realname), + $sender_realname, + PlatformSymbols::getPlatformServerName()), pht( 'Old Username: %s', $old_username), @@ -51,7 +52,10 @@ $new_username)); return id(new PhabricatorMetaMTAMail()) - ->setSubject(pht('[Phabricator] Username Changed')) + ->setSubject( + pht( + '[%s] Username Changed', + PlatformSymbols::getPlatformServerName())) ->setBody($body); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php phabricator-0~git20220903/phabricator/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php --- phabricator-0~git20200925/phabricator/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/mail/PhabricatorPeopleWelcomeMailEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -60,7 +60,9 @@ $message = array(); - $message[] = pht('Welcome to Phabricator!'); + $message[] = pht( + 'Welcome to %s!', + PlatformSymbols::getPlatformServerName()); $message[] = pht( '%s (%s) has created an account for you.', @@ -80,10 +82,10 @@ $use_passwords = PhabricatorPasswordAuthProvider::getPasswordProvider(); if ($use_passwords) { $message[] = pht( - 'To log in to Phabricator, follow this link and set a password:'); + 'To log in, follow this link and set a password:'); $message[] = pht(' %s', $uri); $message[] = pht( - 'After you have set a password, you can log in to Phabricator in '. + 'After you have set a password, you can log in again in '. 'the future by going here:'); $message[] = pht(' %s', $base_uri); } else { @@ -91,7 +93,7 @@ 'To log in to your account for the first time, follow this link:'); $message[] = pht(' %s', $uri); $message[] = pht( - 'After you set up your account, you can log in to Phabricator in '. + 'After you set up your account, you can log in again in '. 'the future by going here:'); $message[] = pht(' %s', $base_uri); } @@ -104,7 +106,11 @@ $message = implode("\n\n", $message); return id(new PhabricatorMetaMTAMail()) - ->setSubject(pht('[Phabricator] Welcome to Phabricator')) + ->setSubject( + pht( + '[%s] Welcome to %s', + PlatformSymbols::getPlatformServerName(), + PlatformSymbols::getPlatformServerName())) ->setBody($message); } @@ -125,7 +131,9 @@ $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if (!$is_serious) { - return pht("Love,\nPhabricator"); + return pht( + "Love,\n%s", + PlatformSymbols::getPlatformServerName()); } return null; diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/management/PhabricatorPeopleManagementApproveWorkflow.php phabricator-0~git20220903/phabricator/src/applications/people/management/PhabricatorPeopleManagementApproveWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/people/management/PhabricatorPeopleManagementApproveWorkflow.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/management/PhabricatorPeopleManagementApproveWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,44 @@ +<?php + + +final class PhabricatorPeopleManagementApproveWorkflow + extends PhabricatorPeopleManagementWorkflow { + + protected function didConstruct() { + $arguments = array_merge( + $this->getUserSelectionArguments(), + array()); + + $this + ->setName('approve') + ->setExamples('**approve** --user __username__') + ->setSynopsis(pht('Approves a user.')) + ->setArguments($arguments); + } + + public function execute(PhutilArgumentParser $args) { + $user = $this->selectUser($args); + $display_name = $user->getUsername(); + + if ($user->getIsApproved()) { + throw new PhutilArgumentUsageException( + pht( + 'User account "%s" is already approved. You can only '. + 'approve accounts that are not yet approved.', + $display_name)); + } + + $xactions = array(); + $xactions[] = $user->getApplicationTransactionTemplate() + ->setTransactionType(PhabricatorUserApproveTransaction::TRANSACTIONTYPE) + ->setNewValue(true); + + $this->applyTransactions($user, $xactions); + + $this->logOkay( + pht('DONE'), + pht('Approved user account "%s".', $display_name)); + + return 0; + } +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/markup/PhabricatorMentionRemarkupRule.php phabricator-0~git20220903/phabricator/src/applications/people/markup/PhabricatorMentionRemarkupRule.php --- phabricator-0~git20200925/phabricator/src/applications/people/markup/PhabricatorMentionRemarkupRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/markup/PhabricatorMentionRemarkupRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -87,24 +87,36 @@ $engine->setTextMetadata($mentioned_key, $mentioned); $context_object = $engine->getConfig('contextObject'); + $policy_object = null; + if ($context_object) { + if ($context_object instanceof PhabricatorPolicyInterface) { + $policy_object = $context_object; + } + } + + if ($policy_object) { + $policy_set = new PhabricatorPolicyFilterSet(); + foreach ($actual_users as $user) { + $policy_set->addCapability( + $user, + $policy_object, + PhabricatorPolicyCapability::CAN_VIEW); + } + } + foreach ($metadata as $username => $tokens) { $exists = isset($actual_users[$username]); - $user_has_no_permission = false; + $user_can_not_view = false; if ($exists) { $user = $actual_users[$username]; - Javelin::initBehavior('phui-hovercards'); // Check if the user has view access to the object she was mentioned in - if ($context_object - && $context_object instanceof PhabricatorPolicyInterface) { - if (!PhabricatorPolicyFilter::hasCapability( + if ($policy_object) { + $user_can_not_view = !$policy_set->hasCapability( $user, - $context_object, - PhabricatorPolicyCapability::CAN_VIEW)) { - // User mentioned has no permission to this object - $user_has_no_permission = true; - } + $policy_object, + PhabricatorPolicyCapability::CAN_VIEW); } $user_href = '/p/'.$user->getUserName().'/'; @@ -112,7 +124,7 @@ if ($engine->isHTMLMailMode()) { $user_href = PhabricatorEnv::getProductionURI($user_href); - if ($user_has_no_permission) { + if ($user_can_not_view) { $colors = ' border-color: #92969D; color: #92969D; @@ -146,8 +158,13 @@ ->setName('@'.$user->getUserName()) ->setHref($user_href); - if ($user_has_no_permission) { - $tag->addClass('phabricator-remarkup-mention-nopermission'); + if ($context_object) { + $tag->setContextObject($context_object); + } + + if ($user_can_not_view) { + $tag->setIcon('fa-eye-slash red'); + $tag->setIsExiled(true); } if ($user->getIsDisabled()) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/query/PhabricatorPeopleLogQuery.php phabricator-0~git20220903/phabricator/src/applications/people/query/PhabricatorPeopleLogQuery.php --- phabricator-0~git20200925/phabricator/src/applications/people/query/PhabricatorPeopleLogQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/query/PhabricatorPeopleLogQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -58,10 +58,6 @@ return new PhabricatorUserLog(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/query/PhabricatorPeopleQuery.php phabricator-0~git20220903/phabricator/src/applications/people/query/PhabricatorPeopleQuery.php --- phabricator-0~git20200925/phabricator/src/applications/people/query/PhabricatorPeopleQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/query/PhabricatorPeopleQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -162,10 +162,6 @@ return new PhabricatorUser(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function didFilterPage(array $users) { if ($this->needProfile) { $user_list = mpull($users, null, 'getPHID'); @@ -341,7 +337,7 @@ (int)$this->isMailingList); } - if (strlen($this->nameLike)) { + if ($this->nameLike !== null) { $where[] = qsprintf( $conn, 'user.username LIKE %~ OR user.realname LIKE %~', diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php phabricator-0~git20220903/phabricator/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php --- phabricator-0~git20200925/phabricator/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -20,10 +20,6 @@ return new PhabricatorUserEmail(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function getPrimaryTableAlias() { return 'email'; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/storage/PhabricatorUserEmail.php phabricator-0~git20220903/phabricator/src/applications/people/storage/PhabricatorUserEmail.php --- phabricator-0~git20200925/phabricator/src/applications/people/storage/PhabricatorUserEmail.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/storage/PhabricatorUserEmail.php 2022-06-14 16:29:55.000000000 +0000 @@ -195,7 +195,9 @@ $signature = null; if (!$is_serious) { - $signature = pht("Get Well Soon,\nPhabricator"); + $signature = pht( + "Get Well Soon,\n%s", + PlatformSymbols::getPlatformServerName()); } $body = sprintf( @@ -211,7 +213,10 @@ id(new PhabricatorMetaMTAMail()) ->addRawTos(array($address)) ->setForceDelivery(true) - ->setSubject(pht('[Phabricator] Email Verification')) + ->setSubject( + pht( + '[%s] Email Verification', + PlatformSymbols::getPlatformServerName())) ->setBody($body) ->setRelatedPHID($user->getPHID()) ->saveAndSend(); @@ -242,15 +247,18 @@ pht('Hi %s', $username), pht( 'This email address (%s) is no longer your primary email address. '. - 'Going forward, Phabricator will send all email to your new primary '. - 'email address (%s).', + 'Going forward, all email will be sent to your new primary email '. + 'address (%s).', $old_address, $new_address)); id(new PhabricatorMetaMTAMail()) ->addRawTos(array($old_address)) ->setForceDelivery(true) - ->setSubject(pht('[Phabricator] Primary Address Changed')) + ->setSubject( + pht( + '[%s] Primary Address Changed', + PlatformSymbols::getPlatformServerName())) ->setBody($body) ->setFrom($user->getPHID()) ->setRelatedPHID($user->getPHID()) @@ -276,13 +284,16 @@ pht('Hi %s', $username), pht( 'This is now your primary email address (%s). Going forward, '. - 'Phabricator will send all email here.', + 'all email will be sent here.', $new_address)); id(new PhabricatorMetaMTAMail()) ->addRawTos(array($new_address)) ->setForceDelivery(true) - ->setSubject(pht('[Phabricator] Primary Address Changed')) + ->setSubject( + pht( + '[%s] Primary Address Changed', + PlatformSymbols::getPlatformServerName())) ->setBody($body) ->setFrom($user->getPHID()) ->setRelatedPHID($user->getPHID()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/storage/PhabricatorUser.php phabricator-0~git20220903/phabricator/src/applications/people/storage/PhabricatorUser.php --- phabricator-0~git20200925/phabricator/src/applications/people/storage/PhabricatorUser.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/storage/PhabricatorUser.php 2022-06-14 16:29:55.000000000 +0000 @@ -275,7 +275,8 @@ $this->setConduitCertificate($this->generateConduitCertificate()); } - if (!strlen($this->getAccountSecret())) { + $secret = $this->getAccountSecret(); + if (($secret === null) || !strlen($secret)) { $this->setAccountSecret(Filesystem::readRandomCharacters(64)); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/view/PhabricatorUserCardView.php phabricator-0~git20220903/phabricator/src/applications/people/view/PhabricatorUserCardView.php --- phabricator-0~git20200925/phabricator/src/applications/people/view/PhabricatorUserCardView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/view/PhabricatorUserCardView.php 2022-06-14 16:29:55.000000000 +0000 @@ -5,6 +5,7 @@ private $profile; private $viewer; private $tag; + private $isExiled; public function setProfile(PhabricatorUser $profile) { $this->profile = $profile; @@ -42,6 +43,15 @@ ); } + public function setIsExiled($is_exiled) { + $this->isExiled = $is_exiled; + return $this; + } + + public function getIsExiled() { + return $this->isExiled; + } + protected function getTagContent() { $user = $this->profile; @@ -108,6 +118,15 @@ } } + if ($this->getIsExiled()) { + $body[] = $this->addItem( + 'fa-eye-slash red', + pht('This user can not see this object.'), + array( + 'project-card-item-exiled', + )); + } + $classes[] = 'project-card-image'; $image = phutil_tag( 'img', @@ -160,17 +179,26 @@ return $card; } - private function addItem($icon, $value) { + private function addItem($icon, $value, $classes = array()) { + $classes[] = 'project-card-item'; + $icon = id(new PHUIIconView()) ->addClass('project-card-item-icon') ->setIcon($icon); + $text = phutil_tag( 'span', array( 'class' => 'project-card-item-text', ), $value); - return phutil_tag_div('project-card-item', array($icon, $text)); + + return phutil_tag( + 'div', + array( + 'class' => implode(' ', $classes), + ), + array($icon, $text)); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/people/xaction/PhabricatorUserApproveTransaction.php phabricator-0~git20220903/phabricator/src/applications/people/xaction/PhabricatorUserApproveTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/people/xaction/PhabricatorUserApproveTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/people/xaction/PhabricatorUserApproveTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,14 +22,16 @@ $actor = $this->getActor(); $title = pht( - 'Phabricator Account "%s" Approved', + '%s Account "%s" Approved', + PlatformSymbols::getPlatformServerName(), $user->getUsername()); $body = sprintf( "%s\n\n %s\n\n", pht( - 'Your Phabricator account (%s) has been approved by %s. You can '. + 'Your %s account (%s) has been approved by %s. You can '. 'login here:', + PlatformSymbols::getPlatformServerName(), $user->getUsername(), $actor->getUsername()), PhabricatorEnv::getProductionURI('/')); @@ -37,7 +39,11 @@ $mail = id(new PhabricatorMetaMTAMail()) ->addTos(array($user->getPHID())) ->addCCs(array($actor->getPHID())) - ->setSubject('[Phabricator] '.$title) + ->setSubject( + pht( + '[%s] %s', + PlatformSymbols::getPlatformServerName(), + $title)) ->setForceDelivery(true) ->setBody($body) ->saveAndSend(); @@ -71,7 +77,10 @@ continue; } - if (!$actor->getIsAdmin()) { + $is_admin = $actor->getIsAdmin(); + $is_omnipotent = $actor->isOmnipotent(); + + if (!$is_admin && !$is_omnipotent) { $errors[] = $this->newInvalidError( pht('You must be an administrator to approve users.')); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/application/PhabricatorPhameApplication.php phabricator-0~git20220903/phabricator/src/applications/phame/application/PhabricatorPhameApplication.php --- phabricator-0~git20200925/phabricator/src/applications/phame/application/PhabricatorPhameApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/application/PhabricatorPhameApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -70,7 +70,11 @@ } public function getBlogRoutes() { - return $this->getLiveRoutes(); + return $this->getLiveRoutes() + array( + '/status/' => 'PhabricatorStatusController', + '/favicon.ico' => 'PhabricatorFaviconController', + '/robots.txt' => 'PhabricatorRobotsBlogController', + ); } private function getLiveRoutes() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/controller/blog/PhameBlogManageController.php phabricator-0~git20220903/phabricator/src/applications/phame/controller/blog/PhameBlogManageController.php --- phabricator-0~git20200925/phabricator/src/applications/phame/controller/blog/PhameBlogManageController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/controller/blog/PhameBlogManageController.php 2022-06-14 16:29:55.000000000 +0000 @@ -143,11 +143,6 @@ ), $feed_uri)); - $engine = id(new PhabricatorMarkupEngine()) - ->setViewer($viewer) - ->addObject($blog, PhameBlog::MARKUP_FIELD_DESCRIPTION) - ->process(); - $description = $blog->getDescription(); if (strlen($description)) { $description = new PHUIRemarkupView($viewer, $description); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/controller/blog/PhameBlogViewController.php phabricator-0~git20220903/phabricator/src/applications/phame/controller/blog/PhameBlogViewController.php --- phabricator-0~git20200925/phabricator/src/applications/phame/controller/blog/PhameBlogViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/controller/blog/PhameBlogViewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -103,7 +103,8 @@ ->setDescription($description) ->setImage($blog->getProfileImageURI()); - $crumbs = $this->buildApplicationCrumbs(); + $crumbs = $this->buildApplicationCrumbs() + ->setBorder(false); $page = $this->newPage() ->setTitle($blog->getName()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/editor/PhameBlogEditor.php phabricator-0~git20220903/phabricator/src/applications/phame/editor/PhameBlogEditor.php --- phabricator-0~git20200925/phabricator/src/applications/phame/editor/PhameBlogEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/editor/PhameBlogEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,8 +21,10 @@ public function getTransactionTypes() { $types = parent::getTransactionTypes(); + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; + $types[] = PhabricatorTransactions::TYPE_INTERACT_POLICY; return $types; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/editor/PhamePostEditEngineLock.php phabricator-0~git20220903/phabricator/src/applications/phame/editor/PhamePostEditEngineLock.php --- phabricator-0~git20200925/phabricator/src/applications/phame/editor/PhamePostEditEngineLock.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/editor/PhamePostEditEngineLock.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,29 @@ +<?php + +final class PhamePostEditEngineLock + extends PhabricatorEditEngineLock { + + public function willPromptUserForLockOverrideWithDialog( + AphrontDialogView $dialog) { + + return $dialog + ->setTitle(pht('Edit Locked Post')) + ->appendParagraph( + pht('Comments are disabled for this post. Edit it anyway?')) + ->addSubmitButton(pht('Edit Post')); + } + + public function willBlockUserInteractionWithDialog( + AphrontDialogView $dialog) { + + return $dialog + ->setTitle(pht('Post Locked')) + ->appendParagraph( + pht('You can not interact with this post because it is locked.')); + } + + public function getLockedObjectDisplayText() { + return pht('Comments have been disabled for this post.'); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/editor/PhamePostEditor.php phabricator-0~git20220903/phabricator/src/applications/phame/editor/PhamePostEditor.php --- phabricator-0~git20200925/phabricator/src/applications/phame/editor/PhamePostEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/editor/PhamePostEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,6 +21,8 @@ public function getTransactionTypes() { $types = parent::getTransactionTypes(); + + $types[] = PhabricatorTransactions::TYPE_INTERACT_POLICY; $types[] = PhabricatorTransactions::TYPE_COMMENT; return $types; diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/policyrule/PhameInheritBlogPolicyRule.php phabricator-0~git20220903/phabricator/src/applications/phame/policyrule/PhameInheritBlogPolicyRule.php --- phabricator-0~git20200925/phabricator/src/applications/phame/policyrule/PhameInheritBlogPolicyRule.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/policyrule/PhameInheritBlogPolicyRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,51 @@ +<?php + +final class PhameInheritBlogPolicyRule + extends PhabricatorPolicyRule { + + public function getObjectPolicyKey() { + return 'phame.blog'; + } + + public function getObjectPolicyName() { + return pht('Same as Blog'); + } + + public function getPolicyExplanation() { + return pht('Use the same policy as the parent blog.'); + } + + public function getRuleDescription() { + return pht('inherit from blog'); + } + + public function getObjectPolicyIcon() { + return 'fa-feed'; + } + + public function canApplyToObject(PhabricatorPolicyInterface $object) { + return ($object instanceof PhamePost); + } + + public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object) { + + // TODO: This is incorrect in the general case, but: "PolicyRule" currently + // does not know which capability it is evaluating (so we can't test for + // the correct capability); and "PhamePost" currently has immutable view + // and edit policies (so we can only arrive here when evaluating the + // interact policy). + + return PhabricatorPolicyFilter::hasCapability( + $viewer, + $object->getBlog(), + PhabricatorPolicyCapability::CAN_INTERACT); + } + + public function getValueControlType() { + return self::CONTROL_TYPE_NONE; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/query/PhameBlogQuery.php phabricator-0~git20220903/phabricator/src/applications/phame/query/PhameBlogQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phame/query/PhameBlogQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/query/PhameBlogQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -45,10 +45,6 @@ return new PhameBlog(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/query/PhamePostQuery.php phabricator-0~git20220903/phabricator/src/applications/phame/query/PhamePostQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phame/query/PhamePostQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/query/PhamePostQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -50,10 +50,6 @@ return new PhamePost(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $posts) { // We require blogs to do visibility checks, so load them unconditionally. $blog_phids = mpull($posts, 'getBlogPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/storage/PhameBlog.php phabricator-0~git20220903/phabricator/src/applications/phame/storage/PhameBlog.php --- phabricator-0~git20200925/phabricator/src/applications/phame/storage/PhameBlog.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/storage/PhameBlog.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,8 +13,6 @@ PhabricatorFulltextInterface, PhabricatorFerretInterface { - const MARKUP_FIELD_DESCRIPTION = 'markup:description'; - protected $name; protected $subtitle; protected $description; @@ -26,6 +24,7 @@ protected $creatorPHID; protected $viewPolicy; protected $editPolicy; + protected $interactPolicy; protected $status; protected $mailKey; protected $profileImagePHID; @@ -56,10 +55,9 @@ 'profileImagePHID' => 'phid?', 'headerImagePHID' => 'phid?', - // T6203/NULLABILITY - // These policies should always be non-null. - 'editPolicy' => 'policy?', - 'viewPolicy' => 'policy?', + 'editPolicy' => 'policy', + 'viewPolicy' => 'policy', + 'interactPolicy' => 'policy', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, @@ -92,7 +90,9 @@ ->setCreatorPHID($actor->getPHID()) ->setStatus(self::STATUS_ACTIVE) ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) - ->setEditPolicy(PhabricatorPolicies::POLICY_USER); + ->setEditPolicy(PhabricatorPolicies::POLICY_USER) + ->setInteractPolicy(PhabricatorPolicies::POLICY_USER); + return $blog; } @@ -154,7 +154,7 @@ $href = PhabricatorEnv::getProductionURI( '/config/edit/policy.allow-public/'); return pht( - 'For custom domains to work, this Phabricator instance must be '. + 'For custom domains to work, this this server must be '. 'configured to allow the public access policy. Configure this '. 'setting %s, or ask an administrator to configure this setting. '. 'The domain can be specified later once this setting has been '. @@ -233,6 +233,7 @@ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_INTERACT, PhabricatorPolicyCapability::CAN_EDIT, ); } @@ -242,6 +243,8 @@ switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); + case PhabricatorPolicyCapability::CAN_INTERACT: + return $this->getInteractPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/phame/storage/PhamePost.php phabricator-0~git20220903/phabricator/src/applications/phame/storage/PhamePost.php --- phabricator-0~git20200925/phabricator/src/applications/phame/storage/PhamePost.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phame/storage/PhamePost.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,11 +11,11 @@ PhabricatorDestructibleInterface, PhabricatorTokenReceiverInterface, PhabricatorConduitResultInterface, + PhabricatorEditEngineLockableInterface, PhabricatorFulltextInterface, PhabricatorFerretInterface { const MARKUP_FIELD_BODY = 'markup:body'; - const MARKUP_FIELD_SUMMARY = 'markup:summary'; protected $bloggerPHID; protected $title; @@ -28,6 +28,7 @@ protected $blogPHID; protected $mailKey; protected $headerImagePHID; + protected $interactPolicy; private $blog = self::ATTACHABLE; private $headerImageFile = self::ATTACHABLE; @@ -41,7 +42,10 @@ ->setBlogPHID($blog->getPHID()) ->attachBlog($blog) ->setDatePublished(PhabricatorTime::getNow()) - ->setVisibility(PhameConstants::VISIBILITY_PUBLISHED); + ->setVisibility(PhameConstants::VISIBILITY_PUBLISHED) + ->setInteractPolicy( + id(new PhameInheritBlogPolicyRule()) + ->getObjectPolicyFullKey()); return $post; } @@ -141,6 +145,8 @@ // T6203/NULLABILITY // This one probably should be nullable? 'datePublished' => 'epoch', + + 'interactPolicy' => 'policy', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, @@ -197,6 +203,7 @@ return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, + PhabricatorPolicyCapability::CAN_INTERACT, ); } @@ -221,6 +228,8 @@ } else { return PhabricatorPolicies::POLICY_NOONE; } + case PhabricatorPolicyCapability::CAN_INTERACT: + return $this->getInteractPolicy(); } } @@ -231,6 +240,8 @@ case PhabricatorPolicyCapability::CAN_VIEW: case PhabricatorPolicyCapability::CAN_EDIT: return ($user->getPHID() == $this->getBloggerPHID()); + case PhabricatorPolicyCapability::CAN_INTERACT: + return false; } } @@ -255,8 +266,6 @@ switch ($field) { case self::MARKUP_FIELD_BODY: return $this->getBody(); - case self::MARKUP_FIELD_SUMMARY: - return PhabricatorMarkupEngine::summarize($this->getBody()); } } @@ -385,4 +394,11 @@ return new PhamePostFerretEngine(); } + +/* -( PhabricatorEditEngineLockableInterface )----------------------------- */ + + public function newEditEngineLock() { + return new PhamePostEditEngineLock(); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/phid/handle/pool/PhabricatorHandleList.php phabricator-0~git20220903/phabricator/src/applications/phid/handle/pool/PhabricatorHandleList.php --- phabricator-0~git20200925/phabricator/src/applications/phid/handle/pool/PhabricatorHandleList.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phid/handle/pool/PhabricatorHandleList.php 2022-06-14 16:29:55.000000000 +0000 @@ -126,22 +126,27 @@ /* -( Iterator )----------------------------------------------------------- */ + #[\ReturnTypeWillChange] public function rewind() { $this->cursor = 0; } + #[\ReturnTypeWillChange] public function current() { return $this->getHandle($this->phids[$this->cursor]); } + #[\ReturnTypeWillChange] public function key() { return $this->phids[$this->cursor]; } + #[\ReturnTypeWillChange] public function next() { ++$this->cursor; } + #[\ReturnTypeWillChange] public function valid() { return ($this->cursor < $this->count); } @@ -150,6 +155,7 @@ /* -( ArrayAccess )-------------------------------------------------------- */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { // NOTE: We're intentionally not loading handles here so that isset() // checks do not trigger fetches. This gives us better bulk loading @@ -162,6 +168,7 @@ return isset($this->map[$offset]); } + #[\ReturnTypeWillChange] public function offsetGet($offset) { if ($this->handles === null) { $this->loadHandles(); @@ -169,10 +176,12 @@ return $this->handles[$offset]; } + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { $this->raiseImmutableException(); } + #[\ReturnTypeWillChange] public function offsetUnset($offset) { $this->raiseImmutableException(); } @@ -189,6 +198,7 @@ /* -( Countable )---------------------------------------------------------- */ + #[\ReturnTypeWillChange] public function count() { return $this->count; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/phid/PhabricatorObjectHandle.php phabricator-0~git20220903/phabricator/src/applications/phid/PhabricatorObjectHandle.php --- phabricator-0~git20200925/phabricator/src/applications/phid/PhabricatorObjectHandle.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phid/PhabricatorObjectHandle.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,6 +32,7 @@ private $tokenIcon; private $commandLineObjectName; private $mailStampName; + private $capabilities = array(); public function setIcon($icon) { $this->icon = $icon; @@ -196,6 +197,10 @@ return $this->status; } + public function isClosed() { + return ($this->status === self::STATUS_CLOSED); + } + public function setFullName($full_name) { $this->fullName = $full_name; return $this; @@ -299,13 +304,21 @@ return $this->renderLinkWithAttributes($name, array()); } - public function renderHovercardLink($name = null) { + public function renderHovercardLink($name = null, $context_phid = null) { Javelin::initBehavior('phui-hovercards'); + $hovercard_spec = array( + 'objectPHID' => $this->getPHID(), + ); + + if ($context_phid) { + $hovercard_spec['contextPHID'] = $context_phid; + } + $attributes = array( 'sigil' => 'hovercard', 'meta' => array( - 'hoverPHID' => $this->getPHID(), + 'hovercardSpec' => $hovercard_spec, ), ); @@ -388,6 +401,72 @@ return idx($types, $this->getType()); } + public function hasCapabilities() { + if (!$this->isComplete()) { + return false; + } + + return ($this->getType() === PhabricatorPeopleUserPHIDType::TYPECONST); + } + + public function attachCapability( + PhabricatorPolicyInterface $object, + $capability, + $has_capability) { + + if (!$this->hasCapabilities()) { + throw new Exception( + pht( + 'Attempting to attach capability ("%s") for object ("%s") to '. + 'handle, but this handle (of type "%s") can not have '. + 'capabilities.', + $capability, + get_class($object), + $this->getType())); + } + + $object_key = $this->getObjectCapabilityKey($object); + $this->capabilities[$object_key][$capability] = $has_capability; + + return $this; + } + + public function hasViewCapability(PhabricatorPolicyInterface $object) { + return $this->hasCapability($object, PhabricatorPolicyCapability::CAN_VIEW); + } + + private function hasCapability( + PhabricatorPolicyInterface $object, + $capability) { + + $object_key = $this->getObjectCapabilityKey($object); + + if (!isset($this->capabilities[$object_key][$capability])) { + throw new Exception( + pht( + 'Attempting to test capability "%s" for handle of type "%s", but '. + 'this capability has not been attached.', + $capability, + $this->getType())); + } + + return $this->capabilities[$object_key][$capability]; + } + + private function getObjectCapabilityKey(PhabricatorPolicyInterface $object) { + $object_phid = $object->getPHID(); + + if (!$object_phid) { + throw new Exception( + pht( + 'Object (of class "%s") has no PHID, so handles can not interact '. + 'with capabilities for it.', + get_class($object))); + } + + return $object_phid; + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/pholio/query/PholioImageQuery.php phabricator-0~git20220903/phabricator/src/applications/pholio/query/PholioImageQuery.php --- phabricator-0~git20200925/phabricator/src/applications/pholio/query/PholioImageQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/pholio/query/PholioImageQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,10 +44,6 @@ return new PholioImage(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneAccountEmailQuery.php phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneAccountEmailQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneAccountEmailQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneAccountEmailQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhortuneAccountEmail(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $addresses) { $accounts = id(new PhortuneAccountQuery()) ->setViewer($this->getViewer()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneAccountQuery.php phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneAccountQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneAccountQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneAccountQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -46,10 +46,6 @@ return new PhortuneAccount(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $accounts) { $query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(mpull($accounts, 'getPHID')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneMerchantQuery.php phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneMerchantQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneMerchantQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneMerchantQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhortuneMerchant(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $merchants) { $query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(mpull($merchants, 'getPHID')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortunePaymentMethodQuery.php phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortunePaymentMethodQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortunePaymentMethodQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortunePaymentMethodQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhortunePaymentMethod(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $methods) { $accounts = id(new PhortuneAccountQuery()) ->setViewer($this->getViewer()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneSubscriptionQuery.php phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneSubscriptionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phortune/query/PhortuneSubscriptionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phortune/query/PhortuneSubscriptionQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -51,10 +51,6 @@ return new PhortuneSubscription(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $subscriptions) { $accounts = id(new PhortuneAccountQuery()) ->setViewer($this->getViewer()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/application/PhabricatorPhragmentApplication.php phabricator-0~git20220903/phabricator/src/applications/phragment/application/PhabricatorPhragmentApplication.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/application/PhabricatorPhragmentApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/application/PhabricatorPhragmentApplication.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -<?php - -final class PhabricatorPhragmentApplication extends PhabricatorApplication { - - public function getName() { - return pht('Phragment'); - } - - public function getBaseURI() { - return '/phragment/'; - } - - public function getShortDescription() { - return pht('Versioned Artifact Storage'); - } - - public function getIcon() { - return 'fa-floppy-o'; - } - - public function getTitleGlyph() { - return "\xE2\x96\x9B"; - } - - public function getApplicationGroup() { - return self::GROUP_UTILITIES; - } - - public function isPrototype() { - return true; - } - - public function getRoutes() { - return array( - '/phragment/' => array( - '' => 'PhragmentBrowseController', - 'browse/(?P<dblob>.*)' => 'PhragmentBrowseController', - 'create/(?P<dblob>.*)' => 'PhragmentCreateController', - 'update/(?P<dblob>.+)' => 'PhragmentUpdateController', - 'policy/(?P<dblob>.+)' => 'PhragmentPolicyController', - 'history/(?P<dblob>.+)' => 'PhragmentHistoryController', - 'zip/(?P<dblob>.+)' => 'PhragmentZIPController', - 'zip@(?P<snapshot>[^/]+)/(?P<dblob>.+)' => 'PhragmentZIPController', - 'version/(?P<id>[0-9]*)/' => 'PhragmentVersionController', - 'patch/(?P<aid>[0-9x]*)/(?P<bid>[0-9]*)/' => 'PhragmentPatchController', - 'revert/(?P<id>[0-9]*)/(?P<dblob>.*)' => 'PhragmentRevertController', - 'snapshot/' => array( - 'create/(?P<dblob>.*)' => 'PhragmentSnapshotCreateController', - 'view/(?P<id>[0-9]*)/' => 'PhragmentSnapshotViewController', - 'delete/(?P<id>[0-9]*)/' => 'PhragmentSnapshotDeleteController', - 'promote/' => array( - 'latest/(?P<dblob>.*)' => 'PhragmentSnapshotPromoteController', - '(?P<id>[0-9]*)/' => 'PhragmentSnapshotPromoteController', - ), - ), - ), - ); - } - - protected function getCustomCapabilities() { - return array( - PhragmentCanCreateCapability::CAPABILITY => array(), - ); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/capability/PhragmentCanCreateCapability.php phabricator-0~git20220903/phabricator/src/applications/phragment/capability/PhragmentCanCreateCapability.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/capability/PhragmentCanCreateCapability.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/capability/PhragmentCanCreateCapability.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -<?php - -final class PhragmentCanCreateCapability extends PhabricatorPolicyCapability { - - const CAPABILITY = 'phragment.create'; - - public function getCapabilityName() { - return pht('Can Create Fragments'); - } - - public function describeCapabilityRejection() { - return pht('You do not have permission to create fragments.'); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/conduit/PhragmentConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/phragment/conduit/PhragmentConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/conduit/PhragmentConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/conduit/PhragmentConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -<?php - -abstract class PhragmentConduitAPIMethod extends ConduitAPIMethod { - - final public function getApplication() { - return PhabricatorApplication::getByClass( - 'PhabricatorPhragmentApplication'); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,192 +0,0 @@ -<?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.'); - } - - protected function defineParamTypes() { - return array( - 'path' => 'required string', - 'state' => 'required dict<string, string>', - ); - } - - protected function defineReturnType() { - return 'nonempty dict'; - } - - protected function defineErrorTypes() { - return array( - 'ERR_BAD_FRAGMENT' => pht('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']); - - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $file = PhabricatorFile::newFromFileData( - $data, - array( - 'name' => 'patch.dmp', - 'ttl.relative' => phutil_units('24 hours in seconds'), - )); - unset($unguarded); - - $patches[$key]['patchURI'] = $file->getDownloadURI(); - } - - return $patches; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -<?php - -final class PhragmentQueryFragmentsConduitAPIMethod - extends PhragmentConduitAPIMethod { - - public function getAPIMethodName() { - return 'phragment.queryfragments'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht('Query fragments based on their paths.'); - } - - protected function defineParamTypes() { - return array( - 'paths' => 'required list<string>', - ); - } - - protected function defineReturnType() { - return 'nonempty dict'; - } - - protected function defineErrorTypes() { - return array( - 'ERR_BAD_FRAGMENT' => pht('No such fragment exists.'), - ); - } - - protected function execute(ConduitAPIRequest $request) { - $paths = $request->getValue('paths'); - - $fragments = id(new PhragmentFragmentQuery()) - ->setViewer($request->getUser()) - ->withPaths($paths) - ->execute(); - $fragments = mpull($fragments, null, 'getPath'); - foreach ($paths as $path) { - if (!array_key_exists($path, $fragments)) { - throw new ConduitException('ERR_BAD_FRAGMENT'); - } - } - - $results = array(); - foreach ($fragments as $path => $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'); - - $result = array(); - foreach ($mappings as $cpath => $child) { - $file_phid = $child->getLatestVersion()->getFilePHID(); - if (!isset($files[$file_phid])) { - // Skip any files we don't have permission to access. - continue; - } - - $file = $files[$file_phid]; - $cpath = substr($child->getPath(), strlen($fragment->getPath()) + 1); - $result[] = array( - 'phid' => $child->getPHID(), - 'phidVersion' => $child->getLatestVersionPHID(), - 'path' => $cpath, - 'hash' => $file->getContentHash(), - 'version' => $child->getLatestVersion()->getSequence(), - 'uri' => $file->getViewURI(), - ); - } - $results[$path] = $result; - } - return $results; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentBrowseController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentBrowseController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentBrowseController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentBrowseController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -<?php - -final class PhragmentBrowseController extends PhragmentController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $dblob = $request->getURIData('dblob'); - - $parents = $this->loadParentFragments($dblob); - if ($parents === null) { - return new Aphront404Response(); - } - $current = nonempty(last($parents), null); - - $path = ''; - if ($current !== null) { - $path = $current->getPath(); - } - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - if ($this->hasApplicationCapability( - PhragmentCanCreateCapability::CAPABILITY)) { - $crumbs->addAction( - id(new PHUIListItemView()) - ->setName(pht('Create Fragment')) - ->setHref($this->getApplicationURI('/create/'.$path)) - ->setIcon('fa-plus-square')); - } - - $current_box = $this->createCurrentFragmentView($current, false); - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - - $fragments = null; - if ($current === null) { - // Find all root fragments. - $fragments = id(new PhragmentFragmentQuery()) - ->setViewer($this->getRequest()->getUser()) - ->needLatestVersion(true) - ->withDepths(array(1)) - ->execute(); - } else { - // Find all child fragments. - $fragments = id(new PhragmentFragmentQuery()) - ->setViewer($this->getRequest()->getUser()) - ->needLatestVersion(true) - ->withLeadingPath($current->getPath().'/') - ->withDepths(array($current->getDepth() + 1)) - ->execute(); - } - - foreach ($fragments as $fragment) { - $item = id(new PHUIObjectItemView()); - $item->setHeader($fragment->getName()); - $item->setHref($fragment->getURI()); - if (!$fragment->isDirectory()) { - $item->addAttribute(pht( - 'Last Updated %s', - phabricator_datetime( - $fragment->getLatestVersion()->getDateCreated(), - $viewer))); - $item->addAttribute(pht( - 'Latest Version %s', - $fragment->getLatestVersion()->getSequence())); - if ($fragment->isDeleted()) { - $item->setDisabled(true); - $item->addAttribute(pht('Deleted')); - } - } else { - $item->addAttribute(pht('Directory')); - } - $list->addItem($item); - } - - $title = pht('Browse Fragments'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $current_box, - $list, - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -<?php - -abstract class PhragmentController extends PhabricatorController { - - protected function loadParentFragments($path) { - $components = explode('/', $path); - - $combinations = array(); - $current = ''; - foreach ($components as $component) { - $current .= '/'.$component; - $current = trim($current, '/'); - if (trim($current) === '') { - continue; - } - - $combinations[] = $current; - } - - $fragments = array(); - $results = id(new PhragmentFragmentQuery()) - ->setViewer($this->getRequest()->getUser()) - ->needLatestVersion(true) - ->withPaths($combinations) - ->execute(); - foreach ($combinations as $combination) { - $found = false; - foreach ($results as $fragment) { - if ($fragment->getPath() === $combination) { - $fragments[] = $fragment; - $found = true; - break; - } - } - if (!$found) { - return null; - } - } - return $fragments; - } - - protected function buildApplicationCrumbsWithPath(array $fragments) { - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb('/', '/phragment/'); - foreach ($fragments as $parent) { - $crumbs->addTextCrumb( - $parent->getName(), - '/phragment/browse/'.$parent->getPath()); - } - return $crumbs; - } - - protected function createCurrentFragmentView($fragment, $is_history_view) { - if ($fragment === null) { - return null; - } - - $viewer = $this->getRequest()->getUser(); - - $snapshot_phids = array(); - $snapshots = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->withPrimaryFragmentPHIDs(array($fragment->getPHID())) - ->execute(); - foreach ($snapshots as $snapshot) { - $snapshot_phids[] = $snapshot->getPHID(); - } - - $file = null; - $file_uri = null; - if (!$fragment->isDirectory()) { - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withPHIDs(array($fragment->getLatestVersion()->getFilePHID())) - ->executeOne(); - if ($file !== null) { - $file_uri = $file->getDownloadURI(); - } - } - - $header = id(new PHUIHeaderView()) - ->setHeader($fragment->getName()) - ->setPolicyObject($fragment) - ->setUser($viewer); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $fragment, - PhabricatorPolicyCapability::CAN_EDIT); - - $zip_uri = $this->getApplicationURI('zip/'.$fragment->getPath()); - - $actions = id(new PhabricatorActionListView()) - ->setUser($viewer) - ->setObject($fragment); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Download Fragment')) - ->setHref($this->isCorrectlyConfigured() ? $file_uri : null) - ->setDisabled($file === null || !$this->isCorrectlyConfigured()) - ->setIcon('fa-download')); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Download Contents as ZIP')) - ->setHref($this->isCorrectlyConfigured() ? $zip_uri : null) - ->setDisabled(!$this->isCorrectlyConfigured()) - ->setIcon('fa-floppy-o')); - if (!$fragment->isDirectory()) { - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Update Fragment')) - ->setHref($this->getApplicationURI('update/'.$fragment->getPath())) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit) - ->setIcon('fa-refresh')); - } else { - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Convert to File')) - ->setHref($this->getApplicationURI('update/'.$fragment->getPath())) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit) - ->setIcon('fa-file-o')); - } - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Set Fragment Policies')) - ->setHref($this->getApplicationURI('policy/'.$fragment->getPath())) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit) - ->setIcon('fa-asterisk')); - if ($is_history_view) { - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('View Child Fragments')) - ->setHref($this->getApplicationURI('browse/'.$fragment->getPath())) - ->setIcon('fa-search-plus')); - } else { - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('View History')) - ->setHref($this->getApplicationURI('history/'.$fragment->getPath())) - ->setIcon('fa-list')); - } - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Create Snapshot')) - ->setHref($this->getApplicationURI( - 'snapshot/create/'.$fragment->getPath())) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit) - ->setIcon('fa-files-o')); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Promote Snapshot to Here')) - ->setHref($this->getApplicationURI( - 'snapshot/promote/latest/'.$fragment->getPath())) - ->setWorkflow(true) - ->setDisabled(!$can_edit) - ->setIcon('fa-arrow-circle-up')); - - $properties = id(new PHUIPropertyListView()) - ->setUser($viewer) - ->setObject($fragment) - ->setActionList($actions); - - if (!$fragment->isDirectory()) { - if ($fragment->isDeleted()) { - $properties->addProperty( - pht('Type'), - pht('File (Deleted)')); - } else { - $properties->addProperty( - pht('Type'), - pht('File')); - } - $properties->addProperty( - pht('Latest Version'), - $viewer->renderHandle($fragment->getLatestVersionPHID())); - } else { - $properties->addProperty( - pht('Type'), - pht('Directory')); - } - - if (count($snapshot_phids) > 0) { - $properties->addProperty( - pht('Snapshots'), - $viewer->renderHandleList($snapshot_phids)); - } - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->addPropertyList($properties); - } - - public function renderConfigurationWarningIfRequired() { - $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); - if ($alt === null) { - return id(new PHUIInfoView()) - ->setTitle(pht( - '%s must be configured!', - 'security.alternate-file-domain')) - ->setSeverity(PHUIInfoView::SEVERITY_ERROR) - ->appendChild( - phutil_tag( - 'p', - array(), - pht( - "Because Phragment generates files (such as ZIP archives and ". - "patches) as they are requested, it requires that you configure ". - "the `%s` option. This option on it's own will also provide ". - "additional security when serving files across Phabricator.", - 'security.alternate-file-domain'))); - } - return null; - } - - /** - * We use this to disable the download links if the alternate domain is - * not configured correctly. Although the download links will mostly work - * for logged in users without an alternate domain, the behaviour is - * reasonably non-consistent and will deny public users, even if policies - * are configured otherwise (because the Files app does not support showing - * the info page to viewers who are not logged in). - */ - public function isCorrectlyConfigured() { - $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain'); - return $alt !== null; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentCreateController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentCreateController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentCreateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentCreateController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -<?php - -final class PhragmentCreateController extends PhragmentController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $dblob = $request->getURIData('dblob'); - - $parent = null; - $parents = $this->loadParentFragments($dblob); - if ($parents === null) { - return new Aphront404Response(); - } - if (count($parents) !== 0) { - $parent = idx($parents, count($parents) - 1, null); - } - - $parent_path = ''; - if ($parent !== null) { - $parent_path = $parent->getPath(); - } - $parent_path = trim($parent_path, '/'); - - $fragment = id(new PhragmentFragment()); - - $error_view = null; - - if ($request->isFormPost()) { - $errors = array(); - - $v_name = $request->getStr('name'); - $v_fileid = $request->getInt('fileID'); - $v_viewpolicy = $request->getStr('viewPolicy'); - $v_editpolicy = $request->getStr('editPolicy'); - - if (strpos($v_name, '/') !== false) { - $errors[] = pht("The fragment name can not contain '/'."); - } - - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withIDs(array($v_fileid)) - ->executeOne(); - if (!$file) { - $errors[] = pht("The specified file doesn't exist."); - } - - if (!count($errors)) { - $depth = 1; - if ($parent !== null) { - $depth = $parent->getDepth() + 1; - } - - PhragmentFragment::createFromFile( - $viewer, - $file, - trim($parent_path.'/'.$v_name, '/'), - $v_viewpolicy, - $v_editpolicy); - - return id(new AphrontRedirectResponse()) - ->setURI('/phragment/browse/'.trim($parent_path.'/'.$v_name, '/')); - } else { - $error_view = id(new PHUIInfoView()) - ->setErrors($errors) - ->setTitle(pht('Errors while creating fragment')); - } - } - - $policies = id(new PhabricatorPolicyQuery()) - ->setViewer($viewer) - ->setObject($fragment) - ->execute(); - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Parent Path')) - ->setDisabled(true) - ->setValue('/'.trim($parent_path.'/', '/'))) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Name')) - ->setName('name')) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('File ID')) - ->setName('fileID')) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setUser($viewer) - ->setName('viewPolicy') - ->setPolicyObject($fragment) - ->setPolicies($policies) - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setUser($viewer) - ->setName('editPolicy') - ->setPolicyObject($fragment) - ->setPolicies($policies) - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Create Fragment')) - ->addCancelButton( - $this->getApplicationURI('browse/'.$parent_path))); - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - $crumbs->addTextCrumb(pht('Create Fragment')); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Create Fragment')) - ->setForm($form); - - if ($error_view) { - $box->setInfoView($error_view); - } - - $title = pht('Create Fragments'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $box, - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentHistoryController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentHistoryController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentHistoryController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentHistoryController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -<?php - -final class PhragmentHistoryController extends PhragmentController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $dblob = $request->getURIData('dblob'); - - $parents = $this->loadParentFragments($dblob); - if ($parents === null) { - return new Aphront404Response(); - } - $current = idx($parents, count($parents) - 1, null); - - $path = $current->getPath(); - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - if ($this->hasApplicationCapability( - PhragmentCanCreateCapability::CAPABILITY)) { - $crumbs->addAction( - id(new PHUIListItemView()) - ->setName(pht('Create Fragment')) - ->setHref($this->getApplicationURI('/create/'.$path)) - ->setIcon('fa-plus-square')); - } - - $current_box = $this->createCurrentFragmentView($current, true); - - $versions = id(new PhragmentFragmentVersionQuery()) - ->setViewer($viewer) - ->withFragmentPHIDs(array($current->getPHID())) - ->execute(); - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - - $file_phids = mpull($versions, 'getFilePHID'); - $files = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withPHIDs($file_phids) - ->execute(); - $files = mpull($files, null, 'getPHID'); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $current, - PhabricatorPolicyCapability::CAN_EDIT); - - $first = true; - foreach ($versions as $version) { - $item = id(new PHUIObjectItemView()); - $item->setHeader(pht('Version %s', $version->getSequence())); - $item->setHref($version->getURI()); - $item->addAttribute(phabricator_datetime( - $version->getDateCreated(), - $viewer)); - - if ($version->getFilePHID() === null) { - $item->setDisabled(true); - $item->addAttribute(pht('Deletion')); - } - - if (!$first && $can_edit) { - $item->addAction(id(new PHUIListItemView()) - ->setIcon('fa-refresh') - ->setRenderNameAsTooltip(true) - ->setWorkflow(true) - ->setName(pht('Revert to Here')) - ->setHref($this->getApplicationURI( - 'revert/'.$version->getID().'/'.$current->getPath()))); - } - - $disabled = !isset($files[$version->getFilePHID()]); - $action = id(new PHUIListItemView()) - ->setIcon('fa-download') - ->setDisabled($disabled || !$this->isCorrectlyConfigured()) - ->setRenderNameAsTooltip(true) - ->setName(pht('Download')); - if (!$disabled && $this->isCorrectlyConfigured()) { - $action->setHref($files[$version->getFilePHID()] - ->getDownloadURI($version->getURI())); - } - $item->addAction($action); - - $list->addItem($item); - - $first = false; - } - - $title = pht('Fragment History'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $current_box, - $list, - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentPatchController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentPatchController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentPatchController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentPatchController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -<?php - -final class PhragmentPatchController extends PhragmentController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $aid = $request->getURIData('aid'); - $bid = $request->getURIData('bid'); - - // If "aid" is "x", then it means the user wants to generate - // a patch of an empty file to the version specified by "bid". - - $ids = array($aid, $bid); - if ($aid === 'x') { - $ids = array($bid); - } - - $versions = id(new PhragmentFragmentVersionQuery()) - ->setViewer($viewer) - ->withIDs($ids) - ->execute(); - - $version_a = null; - if ($aid !== 'x') { - $version_a = idx($versions, $aid, null); - if ($version_a === null) { - return new Aphront404Response(); - } - } - - $version_b = idx($versions, $bid, null); - if ($version_b === null) { - return new Aphront404Response(); - } - - $file_phids = array(); - if ($version_a !== null) { - $file_phids[] = $version_a->getFilePHID(); - } - $file_phids[] = $version_b->getFilePHID(); - - $files = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withPHIDs($file_phids) - ->execute(); - $files = mpull($files, null, 'getPHID'); - - $file_a = null; - if ($version_a != null) { - $file_a = idx($files, $version_a->getFilePHID(), null); - } - $file_b = idx($files, $version_b->getFilePHID(), null); - - $patch = PhragmentPatchUtil::calculatePatch($file_a, $file_b); - - if ($patch === null) { - // There are no differences between the two files, so we output - // an empty patch. - $patch = ''; - } - - $a_sequence = 'x'; - if ($version_a !== null) { - $a_sequence = $version_a->getSequence(); - } - - $name = - $version_b->getFragment()->getName().'.'. - $a_sequence.'.'. - $version_b->getSequence().'.patch'; - - $return = $version_b->getURI(); - if ($request->getExists('return')) { - $return = $request->getStr('return'); - } - - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $result = PhabricatorFile::newFromFileData( - $patch, - array( - 'name' => $name, - 'mime-type' => 'text/plain', - 'ttl.relative' => phutil_units('24 hours in seconds'), - )); - - $result->attachToObject($version_b->getFragmentPHID()); - unset($unguarded); - - return id(new AphrontRedirectResponse()) - ->setURI($result->getDownloadURI($return)); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentPolicyController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentPolicyController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentPolicyController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentPolicyController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -<?php - -final class PhragmentPolicyController extends PhragmentController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $dblob = $request->getURIData('dblob'); - - $parents = $this->loadParentFragments($dblob); - if ($parents === null) { - return new Aphront404Response(); - } - $fragment = idx($parents, count($parents) - 1, null); - - $error_view = null; - - if ($request->isFormPost()) { - $errors = array(); - - $v_view_policy = $request->getStr('viewPolicy'); - $v_edit_policy = $request->getStr('editPolicy'); - $v_replace_children = $request->getBool('replacePoliciesOnChildren'); - - $fragment->setViewPolicy($v_view_policy); - $fragment->setEditPolicy($v_edit_policy); - - $fragment->save(); - - if ($v_replace_children) { - // If you can edit a fragment, you can forcibly set the policies - // on child fragments, regardless of whether you can see them or not. - $children = id(new PhragmentFragmentQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withLeadingPath($fragment->getPath().'/') - ->execute(); - $children_phids = mpull($children, 'getPHID'); - - $fragment->openTransaction(); - foreach ($children as $child) { - $child->setViewPolicy($v_view_policy); - $child->setEditPolicy($v_edit_policy); - $child->save(); - } - $fragment->saveTransaction(); - } - - return id(new AphrontRedirectResponse()) - ->setURI('/phragment/browse/'.$fragment->getPath()); - } - - $policies = id(new PhabricatorPolicyQuery()) - ->setViewer($viewer) - ->setObject($fragment) - ->execute(); - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setName('viewPolicy') - ->setPolicyObject($fragment) - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) - ->setPolicies($policies)) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setName('editPolicy') - ->setPolicyObject($fragment) - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) - ->setPolicies($policies)) - ->appendChild( - id(new AphrontFormCheckboxControl()) - ->addCheckbox( - 'replacePoliciesOnChildren', - 'true', - pht( - 'Replace policies on child fragments with '. - 'the policies above.'))) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Save Fragment Policies')) - ->addCancelButton( - $this->getApplicationURI('browse/'.$fragment->getPath()))); - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - $crumbs->addTextCrumb(pht('Edit Fragment Policies')); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Edit Fragment Policies: %s', $fragment->getPath())) - ->setValidationException(null) - ->setForm($form); - - $title = pht('Edit Fragment Policies'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $box, - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentRevertController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentRevertController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentRevertController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentRevertController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -<?php - -final class PhragmentRevertController extends PhragmentController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - $dblob = $request->getURIData('dblob'); - - $fragment = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->withPaths(array($dblob)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if ($fragment === null) { - return new Aphront404Response(); - } - - $version = id(new PhragmentFragmentVersionQuery()) - ->setViewer($viewer) - ->withFragmentPHIDs(array($fragment->getPHID())) - ->withIDs(array($id)) - ->executeOne(); - if ($version === null) { - return new Aphront404Response(); - } - - if ($request->isDialogFormPost()) { - $file_phid = $version->getFilePHID(); - - $file = null; - if ($file_phid !== null) { - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withPHIDs(array($file_phid)) - ->executeOne(); - if ($file === null) { - throw new Exception( - pht('The file associated with this version was not found.')); - } - } - - if ($file === null) { - $fragment->deleteFile($viewer); - } else { - $fragment->updateFromFile($viewer, $file); - } - - return id(new AphrontRedirectResponse()) - ->setURI($this->getApplicationURI('/history/'.$dblob)); - } - - return $this->createDialog($fragment, $version); - } - - public function createDialog( - PhragmentFragment $fragment, - PhragmentFragmentVersion $version) { - - $viewer = $this->getViewer(); - - $dialog = id(new AphrontDialogView()) - ->setTitle(pht('Really revert this fragment?')) - ->setUser($this->getViewer()) - ->addSubmitButton(pht('Revert')) - ->addCancelButton(pht('Cancel')) - ->appendParagraph(pht( - 'Reverting this fragment to version %d will create a new version of '. - 'the fragment. It will not delete any version history.', - $version->getSequence())); - return id(new AphrontDialogResponse())->setDialog($dialog); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotCreateController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotCreateController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotCreateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotCreateController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,170 +0,0 @@ -<?php - -final class PhragmentSnapshotCreateController extends PhragmentController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $dblob = $request->getURIData('dblob'); - - $parents = $this->loadParentFragments($dblob); - if ($parents === null) { - return new Aphront404Response(); - } - $fragment = nonempty(last($parents), null); - if ($fragment === null) { - return new Aphront404Response(); - } - - PhabricatorPolicyFilter::requireCapability( - $viewer, - $fragment, - PhabricatorPolicyCapability::CAN_EDIT); - - $children = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->needLatestVersion(true) - ->withLeadingPath($fragment->getPath().'/') - ->execute(); - - $errors = array(); - if ($request->isFormPost()) { - - $v_name = $request->getStr('name'); - if (strlen($v_name) === 0) { - $errors[] = pht('You must specify a name.'); - } - if (strpos($v_name, '/') !== false) { - $errors[] = pht('Snapshot names can not contain "/".'); - } - - if (!count($errors)) { - $snapshot = null; - - try { - // Create the snapshot. - $snapshot = id(new PhragmentSnapshot()) - ->setPrimaryFragmentPHID($fragment->getPHID()) - ->setName($v_name) - ->save(); - } catch (AphrontDuplicateKeyQueryException $e) { - $errors[] = pht('A snapshot with this name already exists.'); - } - - if (!count($errors)) { - // Add the primary fragment. - id(new PhragmentSnapshotChild()) - ->setSnapshotPHID($snapshot->getPHID()) - ->setFragmentPHID($fragment->getPHID()) - ->setFragmentVersionPHID($fragment->getLatestVersionPHID()) - ->save(); - - // Add all of the child fragments. - foreach ($children as $child) { - id(new PhragmentSnapshotChild()) - ->setSnapshotPHID($snapshot->getPHID()) - ->setFragmentPHID($child->getPHID()) - ->setFragmentVersionPHID($child->getLatestVersionPHID()) - ->save(); - } - - return id(new AphrontRedirectResponse()) - ->setURI('/phragment/snapshot/view/'.$snapshot->getID()); - } - } - } - - $fragment_sequence = '-'; - if ($fragment->getLatestVersion() !== null) { - $fragment_sequence = $fragment->getLatestVersion()->getSequence(); - } - - $rows = array(); - $rows[] = phutil_tag( - 'tr', - array(), - array( - phutil_tag('th', array(), pht('Fragment')), - phutil_tag('th', array(), pht('Version')), - )); - $rows[] = phutil_tag( - 'tr', - array(), - array( - phutil_tag('td', array(), $fragment->getPath()), - phutil_tag('td', array(), $fragment_sequence), - )); - foreach ($children as $child) { - $sequence = '-'; - if ($child->getLatestVersion() !== null) { - $sequence = $child->getLatestVersion()->getSequence(); - } - $rows[] = phutil_tag( - 'tr', - array(), - array( - phutil_tag('td', array(), $child->getPath()), - phutil_tag('td', array(), $sequence), - )); - } - - $table = phutil_tag( - 'table', - array('class' => 'remarkup-table'), - $rows); - - $container = phutil_tag( - 'div', - array('class' => 'phabricator-remarkup'), - array( - phutil_tag( - 'p', - array(), - pht( - 'The snapshot will contain the following fragments at '. - 'the specified versions: ')), - $table, - )); - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Fragment Path')) - ->setDisabled(true) - ->setValue('/'.$fragment->getPath())) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Snapshot Name')) - ->setName('name')) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Create Snapshot')) - ->addCancelButton( - $this->getApplicationURI('browse/'.$fragment->getPath()))) - ->appendChild( - id(new PHUIFormDividerControl())) - ->appendInstructions($container); - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - $crumbs->addTextCrumb(pht('Create Snapshot')); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Create Snapshot of %s', $fragment->getName())) - ->setFormErrors($errors) - ->setForm($form); - - $title = pht('Create Snapshot'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $box, - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -<?php - -final class PhragmentSnapshotDeleteController extends PhragmentController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - - $snapshot = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->requireCapabilities(array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->withIDs(array($id)) - ->executeOne(); - if ($snapshot === null) { - return new Aphront404Response(); - } - - if ($request->isDialogFormPost()) { - $fragment_uri = $snapshot->getPrimaryFragment()->getURI(); - - $snapshot->delete(); - - return id(new AphrontRedirectResponse()) - ->setURI($fragment_uri); - } - - return $this->createDialog(); - } - - public function createDialog() { - $viewer = $this->getViewer(); - - $dialog = id(new AphrontDialogView()) - ->setTitle(pht('Really delete this snapshot?')) - ->setUser($this->getViewer()) - ->addSubmitButton(pht('Delete')) - ->addCancelButton(pht('Cancel')) - ->appendParagraph(pht( - 'Deleting this snapshot is a permanent operation. You can not '. - 'recover the state of the snapshot.')); - return id(new AphrontDialogResponse())->setDialog($dialog); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,188 +0,0 @@ -<?php - -final class PhragmentSnapshotPromoteController extends PhragmentController { - - private $targetSnapshot; - private $targetFragment; - private $snapshots; - private $options; - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - $dblob = $request->getURIData('dblob'); - - // When the user is promoting a snapshot to the latest version, the - // identifier is a fragment path. - if ($dblob !== null) { - $this->targetFragment = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->requireCapabilities(array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->withPaths(array($dblob)) - ->executeOne(); - if ($this->targetFragment === null) { - return new Aphront404Response(); - } - - $this->snapshots = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->withPrimaryFragmentPHIDs(array($this->targetFragment->getPHID())) - ->execute(); - } - - // When the user is promoting a snapshot to another snapshot, the - // identifier is another snapshot ID. - if ($id !== null) { - $this->targetSnapshot = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->requireCapabilities(array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->withIDs(array($id)) - ->executeOne(); - if ($this->targetSnapshot === null) { - return new Aphront404Response(); - } - - $this->snapshots = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->withPrimaryFragmentPHIDs(array( - $this->targetSnapshot->getPrimaryFragmentPHID(), - )) - ->execute(); - } - - // If there's no identifier, just 404. - if ($this->snapshots === null) { - return new Aphront404Response(); - } - - // Work out what options the user has. - $this->options = mpull( - $this->snapshots, - 'getName', - 'getID'); - if ($id !== null) { - unset($this->options[$id]); - } - - // If there's no options, show a dialog telling the - // user there are no snapshots to promote. - if (count($this->options) === 0) { - return id(new AphrontDialogResponse())->setDialog( - id(new AphrontDialogView()) - ->setTitle(pht('No snapshots to promote')) - ->appendParagraph(pht( - 'There are no snapshots available to promote.')) - ->setUser($this->getViewer()) - ->addCancelButton(pht('Cancel'))); - } - - // Handle snapshot promotion. - if ($request->isDialogFormPost()) { - $snapshot = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->withIDs(array($request->getStr('snapshot'))) - ->executeOne(); - if ($snapshot === null) { - return new Aphront404Response(); - } - - $snapshot->openTransaction(); - // Delete all existing child entries. - $children = id(new PhragmentSnapshotChildQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withSnapshotPHIDs(array($snapshot->getPHID())) - ->execute(); - foreach ($children as $child) { - $child->delete(); - } - - if ($id === null) { - // The user is promoting the snapshot to the latest version. - $children = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->needLatestVersion(true) - ->withLeadingPath($this->targetFragment->getPath().'/') - ->execute(); - - // Add the primary fragment. - id(new PhragmentSnapshotChild()) - ->setSnapshotPHID($snapshot->getPHID()) - ->setFragmentPHID($this->targetFragment->getPHID()) - ->setFragmentVersionPHID( - $this->targetFragment->getLatestVersionPHID()) - ->save(); - - // Add all of the child fragments. - foreach ($children as $child) { - id(new PhragmentSnapshotChild()) - ->setSnapshotPHID($snapshot->getPHID()) - ->setFragmentPHID($child->getPHID()) - ->setFragmentVersionPHID($child->getLatestVersionPHID()) - ->save(); - } - } else { - // The user is promoting the snapshot to another snapshot. We just - // copy the other snapshot's child entries and change the snapshot - // PHID to make it identical. - $children = id(new PhragmentSnapshotChildQuery()) - ->setViewer($viewer) - ->withSnapshotPHIDs(array($this->targetSnapshot->getPHID())) - ->execute(); - foreach ($children as $child) { - id(new PhragmentSnapshotChild()) - ->setSnapshotPHID($snapshot->getPHID()) - ->setFragmentPHID($child->getFragmentPHID()) - ->setFragmentVersionPHID($child->getFragmentVersionPHID()) - ->save(); - } - } - $snapshot->saveTransaction(); - - if ($id === null) { - return id(new AphrontRedirectResponse()) - ->setURI($this->targetFragment->getURI()); - } else { - return id(new AphrontRedirectResponse()) - ->setURI($this->targetSnapshot->getURI()); - } - } - - return $this->createDialog($id); - } - - public function createDialog($id) { - $viewer = $this->getViewer(); - - $dialog = id(new AphrontDialogView()) - ->setTitle(pht('Promote which snapshot?')) - ->setUser($this->getViewer()) - ->addSubmitButton(pht('Promote')) - ->addCancelButton(pht('Cancel')); - - if ($id === null) { - // The user is promoting a snapshot to the latest version. - $dialog->appendParagraph(pht( - 'Select the snapshot you want to promote to the latest version:')); - } else { - // The user is promoting a snapshot to another snapshot. - $dialog->appendParagraph(pht( - "Select the snapshot you want to promote to '%s':", - $this->targetSnapshot->getName())); - } - - $dialog->appendChild( - id(new AphrontFormSelectControl()) - ->setUser($viewer) - ->setName('snapshot') - ->setOptions($this->options)); - - return id(new AphrontDialogResponse())->setDialog($dialog); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotViewController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotViewController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentSnapshotViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentSnapshotViewController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -<?php - -final class PhragmentSnapshotViewController extends PhragmentController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - - $snapshot = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if ($snapshot === null) { - return new Aphront404Response(); - } - - $box = $this->createSnapshotView($snapshot); - - $fragment = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->withPHIDs(array($snapshot->getPrimaryFragmentPHID())) - ->executeOne(); - if ($fragment === null) { - return new Aphront404Response(); - } - - $parents = $this->loadParentFragments($fragment->getPath()); - if ($parents === null) { - return new Aphront404Response(); - } - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - $crumbs->addTextCrumb(pht('"%s" Snapshot', $snapshot->getName())); - - $children = id(new PhragmentSnapshotChildQuery()) - ->setViewer($viewer) - ->needFragments(true) - ->needFragmentVersions(true) - ->withSnapshotPHIDs(array($snapshot->getPHID())) - ->execute(); - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - - foreach ($children as $child) { - $item = id(new PHUIObjectItemView()) - ->setHeader($child->getFragment()->getPath()); - - if ($child->getFragmentVersion() !== null) { - $item - ->setHref($child->getFragmentVersion()->getURI()) - ->addAttribute(pht( - 'Version %s', - $child->getFragmentVersion()->getSequence())); - } else { - $item - ->setHref($child->getFragment()->getURI()) - ->addAttribute(pht('Directory')); - } - - $list->addItem($item); - } - - $title = pht('View Snapshot'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $box, - $list, - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - } - - protected function createSnapshotView($snapshot) { - if ($snapshot === null) { - return null; - } - - $viewer = $this->getRequest()->getUser(); - - $header = id(new PHUIHeaderView()) - ->setHeader(pht('"%s" Snapshot', $snapshot->getName())) - ->setPolicyObject($snapshot) - ->setUser($viewer); - - $zip_uri = $this->getApplicationURI( - 'zip@'.$snapshot->getName(). - '/'.$snapshot->getPrimaryFragment()->getPath()); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $snapshot, - PhabricatorPolicyCapability::CAN_EDIT); - - $actions = id(new PhabricatorActionListView()) - ->setUser($viewer) - ->setObject($snapshot); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Download Snapshot as ZIP')) - ->setHref($this->isCorrectlyConfigured() ? $zip_uri : null) - ->setDisabled(!$this->isCorrectlyConfigured()) - ->setIcon('fa-floppy-o')); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Delete Snapshot')) - ->setHref($this->getApplicationURI( - 'snapshot/delete/'.$snapshot->getID().'/')) - ->setDisabled(!$can_edit) - ->setWorkflow(true) - ->setIcon('fa-times')); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Promote Another Snapshot to Here')) - ->setHref($this->getApplicationURI( - 'snapshot/promote/'.$snapshot->getID().'/')) - ->setDisabled(!$can_edit) - ->setWorkflow(true) - ->setIcon('fa-arrow-up')); - - $properties = id(new PHUIPropertyListView()) - ->setUser($viewer) - ->setObject($snapshot) - ->setActionList($actions); - - $properties->addProperty( - pht('Name'), - $snapshot->getName()); - $properties->addProperty( - pht('Fragment'), - $viewer->renderHandle($snapshot->getPrimaryFragmentPHID())); - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->addPropertyList($properties); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentUpdateController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentUpdateController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentUpdateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentUpdateController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -<?php - -final class PhragmentUpdateController extends PhragmentController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $dblob = $request->getURIData('dblob'); - - $parents = $this->loadParentFragments($dblob); - if ($parents === null) { - return new Aphront404Response(); - } - $fragment = idx($parents, count($parents) - 1, null); - - $error_view = null; - - if ($request->isFormPost()) { - $errors = array(); - - $v_fileid = $request->getInt('fileID'); - - $file = id(new PhabricatorFile())->load($v_fileid); - if ($file === null) { - $errors[] = pht('The specified file doesn\'t exist.'); - } - - if (!count($errors)) { - // If the file is a ZIP archive (has application/zip mimetype) - // then we extract the zip and apply versions for each of the - // individual fragments, creating and deleting files as needed. - if ($file->getMimeType() === 'application/zip') { - $fragment->updateFromZIP($viewer, $file); - } else { - $fragment->updateFromFile($viewer, $file); - } - - return id(new AphrontRedirectResponse()) - ->setURI('/phragment/browse/'.$fragment->getPath()); - } else { - $error_view = id(new PHUIInfoView()) - ->setErrors($errors) - ->setTitle(pht('Errors while updating fragment')); - } - } - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('File ID')) - ->setName('fileID')) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Update Fragment')) - ->addCancelButton( - $this->getApplicationURI('browse/'.$fragment->getPath()))); - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - $crumbs->addTextCrumb(pht('Update Fragment')); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Update Fragment: %s', $fragment->getPath())) - ->setValidationException(null) - ->setForm($form); - - $title = pht('Update Fragment'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $box, - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentVersionController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentVersionController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentVersionController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentVersionController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -<?php - -final class PhragmentVersionController extends PhragmentController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - - $version = id(new PhragmentFragmentVersionQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if ($version === null) { - return new Aphront404Response(); - } - - $parents = $this->loadParentFragments($version->getFragment()->getPath()); - if ($parents === null) { - return new Aphront404Response(); - } - $current = idx($parents, count($parents) - 1, null); - - $crumbs = $this->buildApplicationCrumbsWithPath($parents); - $crumbs->addTextCrumb(pht('View Version %d', $version->getSequence())); - - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withPHIDs(array($version->getFilePHID())) - ->executeOne(); - if ($file !== null) { - $file_uri = $file->getDownloadURI(); - } - - $header = id(new PHUIHeaderView()) - ->setHeader(pht( - '%s at version %d', - $version->getFragment()->getName(), - $version->getSequence())) - ->setPolicyObject($version) - ->setUser($viewer); - - $actions = id(new PhabricatorActionListView()) - ->setUser($viewer) - ->setObject($version); - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Download Version')) - ->setDisabled($file === null || !$this->isCorrectlyConfigured()) - ->setHref($this->isCorrectlyConfigured() ? $file_uri : null) - ->setIcon('fa-download')); - - $properties = id(new PHUIPropertyListView()) - ->setUser($viewer) - ->setObject($version) - ->setActionList($actions); - $properties->addProperty( - pht('File'), - $viewer->renderHandle($version->getFilePHID())); - - $box = id(new PHUIObjectBoxView()) - ->setHeader($header) - ->addPropertyList($properties); - - $title = pht('View Version'); - - $view = array( - $this->renderConfigurationWarningIfRequired(), - $box, - $this->renderPreviousVersionList($version), - ); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - } - - private function renderPreviousVersionList( - PhragmentFragmentVersion $version) { - $viewer = $this->getViewer(); - - $previous_versions = id(new PhragmentFragmentVersionQuery()) - ->setViewer($viewer) - ->withFragmentPHIDs(array($version->getFragmentPHID())) - ->withSequenceBefore($version->getSequence()) - ->execute(); - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - - foreach ($previous_versions as $previous_version) { - $item = id(new PHUIObjectItemView()); - $item->setHeader(pht('Version %s', $previous_version->getSequence())); - $item->setHref($previous_version->getURI()); - $item->addAttribute(phabricator_datetime( - $previous_version->getDateCreated(), - $viewer)); - $patch_uri = $this->getApplicationURI( - 'patch/'.$previous_version->getID().'/'.$version->getID()); - $item->addAction(id(new PHUIListItemView()) - ->setIcon('fa-file-o') - ->setName(pht('Get Patch')) - ->setHref($this->isCorrectlyConfigured() ? $patch_uri : null) - ->setDisabled(!$this->isCorrectlyConfigured())); - $list->addItem($item); - } - - $item = id(new PHUIObjectItemView()); - $item->setHeader(pht('Prior to Version 0')); - $item->addAttribute(pht('Prior to any content (empty file)')); - $item->addAction(id(new PHUIListItemView()) - ->setIcon('fa-file-o') - ->setName(pht('Get Patch')) - ->setHref($this->getApplicationURI( - 'patch/x/'.$version->getID()))); - $list->addItem($item); - - return $list; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentZIPController.php phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentZIPController.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/controller/PhragmentZIPController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/controller/PhragmentZIPController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -<?php - -final class PhragmentZIPController extends PhragmentController { - - private $snapshotCache; - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $dblob = $request->getURIData('dblob'); - $snapshot = $request->getURIData('snapshot'); - - $parents = $this->loadParentFragments($dblob); - if ($parents === null) { - return new Aphront404Response(); - } - $fragment = idx($parents, count($parents) - 1, null); - - if ($snapshot !== null) { - $snapshot = id(new PhragmentSnapshotQuery()) - ->setViewer($viewer) - ->withPrimaryFragmentPHIDs(array($fragment->getPHID())) - ->withNames(array($snapshot)) - ->executeOne(); - if ($snapshot === null) { - return new Aphront404Response(); - } - - $cache = id(new PhragmentSnapshotChildQuery()) - ->setViewer($viewer) - ->needFragmentVersions(true) - ->withSnapshotPHIDs(array($snapshot->getPHID())) - ->execute(); - $this->snapshotCache = mpull( - $cache, - 'getFragmentVersion', - 'getFragmentPHID'); - } - - $temp = new TempFile(); - - $zip = null; - try { - $zip = new ZipArchive(); - } catch (Exception $e) { - $dialog = new AphrontDialogView(); - $dialog->setUser($viewer); - - $inst = pht( - 'This system does not have the ZIP PHP extension installed. This '. - 'is required to download ZIPs from Phragment.'); - - $dialog->setTitle(pht('ZIP Extension Not Installed')); - $dialog->appendParagraph($inst); - - $dialog->addCancelButton('/phragment/browse/'.$dblob); - return id(new AphrontDialogResponse())->setDialog($dialog); - } - - if (!$zip->open((string)$temp, ZipArchive::CREATE)) { - throw new Exception(pht('Unable to create ZIP archive!')); - } - - $mappings = $this->getFragmentMappings( - $fragment, $fragment->getPath(), $snapshot); - - $phids = array(); - foreach ($mappings as $path => $file_phid) { - $phids[] = $file_phid; - } - - $files = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withPHIDs($phids) - ->execute(); - $files = mpull($files, null, 'getPHID'); - foreach ($mappings as $path => $file_phid) { - if (!isset($files[$file_phid])) { - // The path is most likely pointing to a deleted fragment, which - // hence no longer has a file associated with it. - unset($mappings[$path]); - continue; - } - $mappings[$path] = $files[$file_phid]; - } - - foreach ($mappings as $path => $file) { - if ($file !== null) { - $zip->addFromString($path, $file->loadFileData()); - } - } - $zip->close(); - - $zip_name = $fragment->getName(); - if (substr($zip_name, -4) !== '.zip') { - $zip_name .= '.zip'; - } - - $data = Filesystem::readFile((string)$temp); - - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $file = PhabricatorFile::newFromFileData( - $data, - array( - 'name' => $zip_name, - 'ttl.relative' => phutil_units('24 hours in seconds'), - )); - - $file->attachToObject($fragment->getPHID()); - unset($unguarded); - - $return = $fragment->getURI(); - if ($request->getExists('return')) { - $return = $request->getStr('return'); - } - - return id(new AphrontRedirectResponse()) - ->setIsExternal(true) - ->setURI($file->getDownloadURI($return)); - } - - /** - * Returns a list of mappings like array('some/path.txt' => 'file PHID'); - */ - private function getFragmentMappings( - PhragmentFragment $current, - $base_path, - $snapshot) { - $mappings = $current->getFragmentMappings( - $this->getRequest()->getUser(), - $base_path); - - $result = array(); - foreach ($mappings as $path => $fragment) { - $version = $this->getVersion($fragment, $snapshot); - if ($version !== null) { - $result[$path] = $version->getFilePHID(); - } - } - return $result; - } - - private function getVersion($fragment, $snapshot) { - if ($snapshot === null) { - return $fragment->getLatestVersion(); - } else { - return idx($this->snapshotCache, $fragment->getPHID(), null); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/phid/PhragmentFragmentPHIDType.php phabricator-0~git20220903/phabricator/src/applications/phragment/phid/PhragmentFragmentPHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/phid/PhragmentFragmentPHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/phid/PhragmentFragmentPHIDType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -<?php - -final class PhragmentFragmentPHIDType extends PhabricatorPHIDType { - - const TYPECONST = 'PHRF'; - - public function getTypeName() { - return pht('Fragment'); - } - - public function newObject() { - return new PhragmentFragment(); - } - - public function getPHIDTypeApplicationClass() { - return 'PhabricatorPhragmentApplication'; - } - - protected function buildQueryForObjects( - PhabricatorObjectQuery $query, - array $phids) { - - return id(new PhragmentFragmentQuery()) - ->withPHIDs($phids); - } - - public function loadHandles( - PhabricatorHandleQuery $query, - array $handles, - array $objects) { - - $viewer = $query->getViewer(); - foreach ($handles as $phid => $handle) { - $fragment = $objects[$phid]; - - $handle->setName(pht( - 'Fragment %s: %s', - $fragment->getID(), - $fragment->getName())); - $handle->setURI($fragment->getURI()); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php phabricator-0~git20220903/phabricator/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -<?php - -final class PhragmentFragmentVersionPHIDType extends PhabricatorPHIDType { - - const TYPECONST = 'PHRV'; - - public function getTypeName() { - return pht('Fragment Version'); - } - - public function newObject() { - return new PhragmentFragmentVersion(); - } - - public function getPHIDTypeApplicationClass() { - return 'PhabricatorPhragmentApplication'; - } - - protected function buildQueryForObjects( - PhabricatorObjectQuery $query, - array $phids) { - - return id(new PhragmentFragmentVersionQuery()) - ->withPHIDs($phids); - } - - public function loadHandles( - PhabricatorHandleQuery $query, - array $handles, - array $objects) { - - $viewer = $query->getViewer(); - foreach ($handles as $phid => $handle) { - $version = $objects[$phid]; - - $handle->setName(pht( - 'Fragment Version %d: %s', - $version->getSequence(), - $version->getFragment()->getName())); - $handle->setURI($version->getURI()); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php phabricator-0~git20220903/phabricator/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -<?php - -final class PhragmentSnapshotPHIDType extends PhabricatorPHIDType { - - const TYPECONST = 'PHRS'; - - public function getTypeName() { - return pht('Snapshot'); - } - - public function newObject() { - return new PhragmentSnapshot(); - } - - public function getPHIDTypeApplicationClass() { - return 'PhabricatorPhragmentApplication'; - } - - protected function buildQueryForObjects( - PhabricatorObjectQuery $query, - array $phids) { - - return id(new PhragmentSnapshotQuery()) - ->withPHIDs($phids); - } - - public function loadHandles( - PhabricatorHandleQuery $query, - array $handles, - array $objects) { - - $viewer = $query->getViewer(); - foreach ($handles as $phid => $handle) { - $snapshot = $objects[$phid]; - - $handle->setName(pht( - 'Snapshot: %s', - $snapshot->getName())); - $handle->setURI($snapshot->getURI()); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentFragmentQuery.php phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentFragmentQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentFragmentQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentFragmentQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -<?php - -final class PhragmentFragmentQuery - extends PhabricatorCursorPagedPolicyAwareQuery { - - private $ids; - private $phids; - private $paths; - private $leadingPath; - private $depths; - private $needLatestVersion; - - public function withIDs(array $ids) { - $this->ids = $ids; - return $this; - } - - public function withPHIDs(array $phids) { - $this->phids = $phids; - return $this; - } - - public function withPaths(array $paths) { - $this->paths = $paths; - return $this; - } - - public function withLeadingPath($path) { - $this->leadingPath = $path; - return $this; - } - - public function withDepths($depths) { - $this->depths = $depths; - return $this; - } - - public function needLatestVersion($need_latest_version) { - $this->needLatestVersion = $need_latest_version; - return $this; - } - - protected function loadPage() { - $table = new PhragmentFragment(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); - } - - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); - - if ($this->ids) { - $where[] = qsprintf( - $conn, - 'id IN (%Ld)', - $this->ids); - } - - if ($this->phids) { - $where[] = qsprintf( - $conn, - 'phid IN (%Ls)', - $this->phids); - } - - if ($this->paths) { - $where[] = qsprintf( - $conn, - 'path IN (%Ls)', - $this->paths); - } - - if ($this->leadingPath) { - $where[] = qsprintf( - $conn, - 'path LIKE %>', - $this->leadingPath); - } - - if ($this->depths) { - $where[] = qsprintf( - $conn, - 'depth IN (%Ld)', - $this->depths); - } - - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); - } - - protected function didFilterPage(array $page) { - if ($this->needLatestVersion) { - $versions = array(); - - $version_phids = array_filter(mpull($page, 'getLatestVersionPHID')); - if ($version_phids) { - $versions = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($version_phids) - ->setParentQuery($this) - ->execute(); - $versions = mpull($versions, null, 'getPHID'); - } - - foreach ($page as $key => $fragment) { - $version_phid = $fragment->getLatestVersionPHID(); - if (empty($versions[$version_phid])) { - continue; - } - $fragment->attachLatestVersion($versions[$version_phid]); - } - } - - return $page; - } - - public function getQueryApplicationClass() { - return 'PhabricatorPhragmentApplication'; - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentFragmentVersionQuery.php phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentFragmentVersionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentFragmentVersionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentFragmentVersionQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -<?php - -final class PhragmentFragmentVersionQuery - extends PhabricatorCursorPagedPolicyAwareQuery { - - private $ids; - private $phids; - private $fragmentPHIDs; - private $sequences; - private $sequenceBefore; - - public function withIDs(array $ids) { - $this->ids = $ids; - return $this; - } - - public function withPHIDs(array $phids) { - $this->phids = $phids; - return $this; - } - - public function withFragmentPHIDs(array $fragment_phids) { - $this->fragmentPHIDs = $fragment_phids; - return $this; - } - - public function withSequences(array $sequences) { - $this->sequences = $sequences; - return $this; - } - - public function withSequenceBefore($current) { - $this->sequenceBefore = $current; - return $this; - } - - protected function loadPage() { - $table = new PhragmentFragmentVersion(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); - } - - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); - - if ($this->ids) { - $where[] = qsprintf( - $conn, - 'id IN (%Ld)', - $this->ids); - } - - if ($this->phids) { - $where[] = qsprintf( - $conn, - 'phid IN (%Ls)', - $this->phids); - } - - if ($this->fragmentPHIDs) { - $where[] = qsprintf( - $conn, - 'fragmentPHID IN (%Ls)', - $this->fragmentPHIDs); - } - - if ($this->sequences) { - $where[] = qsprintf( - $conn, - 'sequence IN (%Ld)', - $this->sequences); - } - - if ($this->sequenceBefore !== null) { - $where[] = qsprintf( - $conn, - 'sequence < %d', - $this->sequenceBefore); - } - - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); - } - - protected function willFilterPage(array $page) { - $fragments = array(); - - $fragment_phids = array_filter(mpull($page, 'getFragmentPHID')); - if ($fragment_phids) { - $fragments = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($fragment_phids) - ->setParentQuery($this) - ->execute(); - $fragments = mpull($fragments, null, 'getPHID'); - } - - foreach ($page as $key => $version) { - $fragment_phid = $version->getFragmentPHID(); - if (empty($fragments[$fragment_phid])) { - unset($page[$key]); - continue; - } - $version->attachFragment($fragments[$fragment_phid]); - } - - return $page; - } - - public function getQueryApplicationClass() { - return 'PhabricatorPhragmentApplication'; - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentSnapshotChildQuery.php phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentSnapshotChildQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentSnapshotChildQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentSnapshotChildQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,174 +0,0 @@ -<?php - -final class PhragmentSnapshotChildQuery - extends PhabricatorCursorPagedPolicyAwareQuery { - - private $ids; - private $snapshotPHIDs; - private $fragmentPHIDs; - private $fragmentVersionPHIDs; - private $needFragments; - private $needFragmentVersions; - - public function withIDs(array $ids) { - $this->ids = $ids; - return $this; - } - - public function withSnapshotPHIDs(array $snapshot_phids) { - $this->snapshotPHIDs = $snapshot_phids; - return $this; - } - - public function withFragmentPHIDs(array $fragment_phids) { - $this->fragmentPHIDs = $fragment_phids; - return $this; - } - - public function withFragmentVersionPHIDs(array $fragment_version_phids) { - $this->fragmentVersionPHIDs = $fragment_version_phids; - return $this; - } - - public function needFragments($need_fragments) { - $this->needFragments = $need_fragments; - return $this; - } - - public function needFragmentVersions($need_fragment_versions) { - $this->needFragmentVersions = $need_fragment_versions; - return $this; - } - - protected function loadPage() { - $table = new PhragmentSnapshotChild(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); - } - - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); - - if ($this->ids) { - $where[] = qsprintf( - $conn, - 'id IN (%Ld)', - $this->ids); - } - - if ($this->snapshotPHIDs) { - $where[] = qsprintf( - $conn, - 'snapshotPHID IN (%Ls)', - $this->snapshotPHIDs); - } - - if ($this->fragmentPHIDs) { - $where[] = qsprintf( - $conn, - 'fragmentPHID IN (%Ls)', - $this->fragmentPHIDs); - } - - if ($this->fragmentVersionPHIDs) { - $where[] = qsprintf( - $conn, - 'fragmentVersionPHID IN (%Ls)', - $this->fragmentVersionPHIDs); - } - - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); - } - - protected function willFilterPage(array $page) { - $snapshots = array(); - - $snapshot_phids = array_filter(mpull($page, 'getSnapshotPHID')); - if ($snapshot_phids) { - $snapshots = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($snapshot_phids) - ->setParentQuery($this) - ->execute(); - $snapshots = mpull($snapshots, null, 'getPHID'); - } - - foreach ($page as $key => $child) { - $snapshot_phid = $child->getSnapshotPHID(); - if (empty($snapshots[$snapshot_phid])) { - unset($page[$key]); - continue; - } - $child->attachSnapshot($snapshots[$snapshot_phid]); - } - - return $page; - } - - protected function didFilterPage(array $page) { - if ($this->needFragments) { - $fragments = array(); - - $fragment_phids = array_filter(mpull($page, 'getFragmentPHID')); - if ($fragment_phids) { - $fragments = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($fragment_phids) - ->setParentQuery($this) - ->execute(); - $fragments = mpull($fragments, null, 'getPHID'); - } - - foreach ($page as $key => $child) { - $fragment_phid = $child->getFragmentPHID(); - if (empty($fragments[$fragment_phid])) { - unset($page[$key]); - continue; - } - $child->attachFragment($fragments[$fragment_phid]); - } - } - - if ($this->needFragmentVersions) { - $fragment_versions = array(); - - $fragment_version_phids = array_filter(mpull( - $page, - 'getFragmentVersionPHID')); - if ($fragment_version_phids) { - $fragment_versions = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($fragment_version_phids) - ->setParentQuery($this) - ->execute(); - $fragment_versions = mpull($fragment_versions, null, 'getPHID'); - } - - foreach ($page as $key => $child) { - $fragment_version_phid = $child->getFragmentVersionPHID(); - if (empty($fragment_versions[$fragment_version_phid])) { - continue; - } - $child->attachFragmentVersion( - $fragment_versions[$fragment_version_phid]); - } - } - - return $page; - } - - public function getQueryApplicationClass() { - return 'PhabricatorPhragmentApplication'; - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentSnapshotQuery.php phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentSnapshotQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/query/PhragmentSnapshotQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/query/PhragmentSnapshotQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -<?php - -final class PhragmentSnapshotQuery - extends PhabricatorCursorPagedPolicyAwareQuery { - - private $ids; - private $phids; - private $primaryFragmentPHIDs; - private $names; - - public function withIDs(array $ids) { - $this->ids = $ids; - return $this; - } - - public function withPHIDs(array $phids) { - $this->phids = $phids; - return $this; - } - - public function withPrimaryFragmentPHIDs(array $primary_fragment_phids) { - $this->primaryFragmentPHIDs = $primary_fragment_phids; - return $this; - } - - public function withNames(array $names) { - $this->names = $names; - return $this; - } - - protected function loadPage() { - $table = new PhragmentSnapshot(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); - } - - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); - - if ($this->ids !== null) { - $where[] = qsprintf( - $conn, - 'id IN (%Ld)', - $this->ids); - } - - if ($this->phids !== null) { - $where[] = qsprintf( - $conn, - 'phid IN (%Ls)', - $this->phids); - } - - if ($this->primaryFragmentPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'primaryFragmentPHID IN (%Ls)', - $this->primaryFragmentPHIDs); - } - - if ($this->names !== null) { - $where[] = qsprintf( - $conn, - 'name IN (%Ls)', - $this->names); - } - - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); - } - - protected function willFilterPage(array $page) { - $fragments = array(); - - $fragment_phids = array_filter(mpull($page, 'getPrimaryFragmentPHID')); - if ($fragment_phids) { - $fragments = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($fragment_phids) - ->setParentQuery($this) - ->execute(); - $fragments = mpull($fragments, null, 'getPHID'); - } - - foreach ($page as $key => $snapshot) { - $fragment_phid = $snapshot->getPrimaryFragmentPHID(); - if (empty($fragments[$fragment_phid])) { - unset($page[$key]); - continue; - } - $snapshot->attachPrimaryFragment($fragments[$fragment_phid]); - } - - return $page; - } - - public function getQueryApplicationClass() { - return 'PhabricatorPhragmentApplication'; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentDAO.php phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentDAO.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentDAO.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentDAO.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -<?php - -abstract class PhragmentDAO extends PhabricatorLiskDAO { - - public function getApplicationName() { - return 'phragment'; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentFragment.php phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentFragment.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentFragment.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentFragment.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,349 +0,0 @@ -<?php - -final class PhragmentFragment extends PhragmentDAO - implements PhabricatorPolicyInterface { - - protected $path; - protected $depth; - protected $latestVersionPHID; - protected $viewPolicy; - protected $editPolicy; - - private $latestVersion = self::ATTACHABLE; - private $file = self::ATTACHABLE; - - protected function getConfiguration() { - return array( - self::CONFIG_AUX_PHID => true, - self::CONFIG_COLUMN_SCHEMA => array( - 'path' => 'text128', - 'depth' => 'uint32', - 'latestVersionPHID' => 'phid?', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_path' => array( - 'columns' => array('path'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - PhragmentFragmentPHIDType::TYPECONST); - } - - public function getURI() { - return '/phragment/browse/'.$this->getPath(); - } - - public function getName() { - return basename($this->path); - } - - public function getFile() { - return $this->assertAttached($this->file); - } - - public function attachFile(PhabricatorFile $file) { - return $this->file = $file; - } - - public function isDirectory() { - return $this->latestVersionPHID === null; - } - - public function isDeleted() { - return $this->getLatestVersion()->getFilePHID() === null; - } - - public function getLatestVersion() { - if ($this->latestVersionPHID === null) { - return null; - } - return $this->assertAttached($this->latestVersion); - } - - public function attachLatestVersion(PhragmentFragmentVersion $version) { - return $this->latestVersion = $version; - } - - -/* -( Updating ) --------------------------------------------------------- */ - - - /** - * Create a new fragment from a file. - */ - public static function createFromFile( - PhabricatorUser $viewer, - PhabricatorFile $file = null, - $path = null, - $view_policy = null, - $edit_policy = null) { - - $fragment = id(new PhragmentFragment()); - $fragment->setPath($path); - $fragment->setDepth(count(explode('/', $path))); - $fragment->setLatestVersionPHID(null); - $fragment->setViewPolicy($view_policy); - $fragment->setEditPolicy($edit_policy); - $fragment->save(); - - // Directory fragments have no versions associated with them, so we - // just return the fragment at this point. - if ($file === null) { - return $fragment; - } - - if ($file->getMimeType() === 'application/zip') { - $fragment->updateFromZIP($viewer, $file); - } else { - $fragment->updateFromFile($viewer, $file); - } - - return $fragment; - } - - - /** - * Set the specified file as the next version for the fragment. - */ - public function updateFromFile( - PhabricatorUser $viewer, - PhabricatorFile $file) { - - $existing = id(new PhragmentFragmentVersionQuery()) - ->setViewer($viewer) - ->withFragmentPHIDs(array($this->getPHID())) - ->execute(); - $sequence = count($existing); - - $this->openTransaction(); - $version = id(new PhragmentFragmentVersion()); - $version->setSequence($sequence); - $version->setFragmentPHID($this->getPHID()); - $version->setFilePHID($file->getPHID()); - $version->save(); - - $this->setLatestVersionPHID($version->getPHID()); - $this->save(); - $this->saveTransaction(); - - $file->attachToObject($version->getPHID()); - } - - /** - * Apply the specified ZIP archive onto the fragment, removing - * and creating fragments as needed. - */ - public function updateFromZIP( - PhabricatorUser $viewer, - PhabricatorFile $file) { - - if ($file->getMimeType() !== 'application/zip') { - throw new Exception( - pht("File must have mimetype '%s'.", 'application/zip')); - } - - // First apply the ZIP as normal. - $this->updateFromFile($viewer, $file); - - // Ensure we have ZIP support. - $zip = null; - try { - $zip = new ZipArchive(); - } catch (Exception $e) { - // The server doesn't have php5-zip, so we can't do recursive updates. - return; - } - - $temp = new TempFile(); - Filesystem::writeFile($temp, $file->loadFileData()); - if (!$zip->open($temp)) { - throw new Exception(pht('Unable to open ZIP.')); - } - - // Get all of the paths and their data from the ZIP. - $mappings = array(); - for ($i = 0; $i < $zip->numFiles; $i++) { - $path = trim($zip->getNameIndex($i), '/'); - $stream = $zip->getStream($path); - $data = null; - // If the stream is false, then it is a directory entry. We leave - // $data set to null for directories so we know not to create a - // version entry for them. - if ($stream !== false) { - $data = stream_get_contents($stream); - fclose($stream); - } - $mappings[$path] = $data; - } - - // We need to detect any directories that are in the ZIP folder that - // aren't explicitly noted in the ZIP. This can happen if the file - // entries in the ZIP look like: - // - // * something/blah.png - // * something/other.png - // * test.png - // - // Where there is no explicit "something/" entry. - foreach ($mappings as $path_key => $data) { - if ($data === null) { - continue; - } - $directory = dirname($path_key); - while ($directory !== '.') { - if (!array_key_exists($directory, $mappings)) { - $mappings[$directory] = null; - } - if (dirname($directory) === $directory) { - // dirname() will not reduce this directory any further; to - // prevent infinite loop we just break out here. - break; - } - $directory = dirname($directory); - } - } - - // Adjust the paths relative to this fragment so we can look existing - // fragments up in the DB. - $base_path = $this->getPath(); - $paths = array(); - foreach ($mappings as $p => $data) { - $paths[] = $base_path.'/'.$p; - } - - // FIXME: What happens when a child exists, but the current user - // can't see it. We're going to create a new child with the exact - // same path and then bad things will happen. - $children = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->needLatestVersion(true) - ->withLeadingPath($this->getPath().'/') - ->execute(); - $children = mpull($children, null, 'getPath'); - - // Iterate over the existing fragments. - foreach ($children as $full_path => $child) { - $path = substr($full_path, strlen($base_path) + 1); - if (array_key_exists($path, $mappings)) { - if ($child->isDirectory() && $mappings[$path] === null) { - // Don't create a version entry for a directory - // (unless it's been converted into a file). - continue; - } - - // The file is being updated. - $file = PhabricatorFile::newFromFileData( - $mappings[$path], - array('name' => basename($path))); - $child->updateFromFile($viewer, $file); - } else { - // The file is being deleted. - $child->deleteFile($viewer); - } - } - - // Iterate over the mappings to find new files. - foreach ($mappings as $path => $data) { - if (!array_key_exists($base_path.'/'.$path, $children)) { - // The file is being created. If the data is null, - // then this is explicitly a directory being created. - $file = null; - if ($mappings[$path] !== null) { - $file = PhabricatorFile::newFromFileData( - $mappings[$path], - array('name' => basename($path))); - } - self::createFromFile( - $viewer, - $file, - $base_path.'/'.$path, - $this->getViewPolicy(), - $this->getEditPolicy()); - } - } - } - - /** - * Delete the contents of the specified fragment. - */ - public function deleteFile(PhabricatorUser $viewer) { - $existing = id(new PhragmentFragmentVersionQuery()) - ->setViewer($viewer) - ->withFragmentPHIDs(array($this->getPHID())) - ->execute(); - $sequence = count($existing); - - $this->openTransaction(); - $version = id(new PhragmentFragmentVersion()); - $version->setSequence($sequence); - $version->setFragmentPHID($this->getPHID()); - $version->setFilePHID(null); - $version->save(); - - $this->setLatestVersionPHID($version->getPHID()); - $this->save(); - $this->saveTransaction(); - } - - -/* -( Utility ) ---------------------------------------------------------- */ - - - public function getFragmentMappings( - PhabricatorUser $viewer, - $base_path) { - - $children = id(new PhragmentFragmentQuery()) - ->setViewer($viewer) - ->needLatestVersion(true) - ->withLeadingPath($this->getPath().'/') - ->withDepths(array($this->getDepth() + 1)) - ->execute(); - - if (count($children) === 0) { - $path = substr($this->getPath(), strlen($base_path) + 1); - return array($path => $this); - } else { - $mappings = array(); - foreach ($children as $child) { - $child_mappings = $child->getFragmentMappings( - $viewer, - $base_path); - foreach ($child_mappings as $key => $value) { - $mappings[$key] = $value; - } - } - return $mappings; - } - } - - -/* -( Policy Interface )--------------------------------------------------- */ - - - public function getCapabilities() { - return array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - ); - } - - public function getPolicy($capability) { - switch ($capability) { - case PhabricatorPolicyCapability::CAN_VIEW: - return $this->getViewPolicy(); - case PhabricatorPolicyCapability::CAN_EDIT: - return $this->getEditPolicy(); - } - } - - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - return false; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentFragmentVersion.php phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentFragmentVersion.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentFragmentVersion.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentFragmentVersion.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -<?php - -final class PhragmentFragmentVersion extends PhragmentDAO - implements PhabricatorPolicyInterface { - - protected $sequence; - protected $fragmentPHID; - protected $filePHID; - - private $fragment = self::ATTACHABLE; - private $file = self::ATTACHABLE; - - protected function getConfiguration() { - return array( - self::CONFIG_AUX_PHID => true, - self::CONFIG_COLUMN_SCHEMA => array( - 'sequence' => 'uint32', - 'filePHID' => 'phid?', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_version' => array( - 'columns' => array('fragmentPHID', 'sequence'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - PhragmentFragmentVersionPHIDType::TYPECONST); - } - - public function getURI() { - return '/phragment/version/'.$this->getID().'/'; - } - - public function getFragment() { - return $this->assertAttached($this->fragment); - } - - public function attachFragment(PhragmentFragment $fragment) { - return $this->fragment = $fragment; - } - - public function getFile() { - return $this->assertAttached($this->file); - } - - public function attachFile(PhabricatorFile $file) { - return $this->file = $file; - } - - public function getCapabilities() { - return array( - PhabricatorPolicyCapability::CAN_VIEW, - ); - } - - public function getPolicy($capability) { - return $this->getFragment()->getPolicy($capability); - } - - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - return $this->getFragment()->hasAutomaticCapability($capability, $viewer); - } - - public function describeAutomaticCapability($capability) { - return $this->getFragment()->describeAutomaticCapability($capability); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentSchemaSpec.php phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentSchemaSpec.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentSchemaSpec.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentSchemaSpec.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -<?php - -final class PhragmentSchemaSpec extends PhabricatorConfigSchemaSpec { - - public function buildSchemata() { - $this->buildEdgeSchemata(new PhragmentFragment()); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentSnapshotChild.php phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentSnapshotChild.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentSnapshotChild.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentSnapshotChild.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -<?php - -final class PhragmentSnapshotChild extends PhragmentDAO - implements PhabricatorPolicyInterface { - - protected $snapshotPHID; - protected $fragmentPHID; - protected $fragmentVersionPHID; - - private $snapshot = self::ATTACHABLE; - private $fragment = self::ATTACHABLE; - private $fragmentVersion = self::ATTACHABLE; - - protected function getConfiguration() { - return array( - self::CONFIG_COLUMN_SCHEMA => array( - 'fragmentVersionPHID' => 'phid?', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_child' => array( - 'columns' => array( - 'snapshotPHID', - 'fragmentPHID', - 'fragmentVersionPHID', - ), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function getSnapshot() { - return $this->assertAttached($this->snapshot); - } - - public function attachSnapshot(PhragmentSnapshot $snapshot) { - return $this->snapshot = $snapshot; - } - - public function getFragment() { - return $this->assertAttached($this->fragment); - } - - public function attachFragment(PhragmentFragment $fragment) { - return $this->fragment = $fragment; - } - - public function getFragmentVersion() { - if ($this->fragmentVersionPHID === null) { - return null; - } - return $this->assertAttached($this->fragmentVersion); - } - - public function attachFragmentVersion(PhragmentFragmentVersion $version) { - return $this->fragmentVersion = $version; - } - - -/* -( Policy Interface )--------------------------------------------------- */ - - - public function getCapabilities() { - return array( - PhabricatorPolicyCapability::CAN_VIEW, - ); - } - - public function getPolicy($capability) { - return $this->getSnapshot()->getPolicy($capability); - } - - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - return $this->getSnapshot() - ->hasAutomaticCapability($capability, $viewer); - } - - public function describeAutomaticCapability($capability) { - return $this->getSnapshot() - ->describeAutomaticCapability($capability); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentSnapshot.php phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentSnapshot.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/storage/PhragmentSnapshot.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/storage/PhragmentSnapshot.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -<?php - -final class PhragmentSnapshot extends PhragmentDAO - implements PhabricatorPolicyInterface { - - protected $primaryFragmentPHID; - protected $name; - - private $primaryFragment = self::ATTACHABLE; - - protected function getConfiguration() { - return array( - self::CONFIG_AUX_PHID => true, - self::CONFIG_COLUMN_SCHEMA => array( - 'name' => 'text128', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_name' => array( - 'columns' => array('primaryFragmentPHID', 'name'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - PhragmentSnapshotPHIDType::TYPECONST); - } - - public function getURI() { - return '/phragment/snapshot/view/'.$this->getID().'/'; - } - - public function getPrimaryFragment() { - return $this->assertAttached($this->primaryFragment); - } - - public function attachPrimaryFragment(PhragmentFragment $fragment) { - return $this->primaryFragment = $fragment; - } - - public function delete() { - $children = id(new PhragmentSnapshotChild()) - ->loadAllWhere('snapshotPHID = %s', $this->getPHID()); - $this->openTransaction(); - foreach ($children as $child) { - $child->delete(); - } - $result = parent::delete(); - $this->saveTransaction(); - return $result; - } - - -/* -( Policy Interface )--------------------------------------------------- */ - - - public function getCapabilities() { - return $this->getPrimaryFragment()->getCapabilities(); - } - - public function getPolicy($capability) { - return $this->getPrimaryFragment()->getPolicy($capability); - } - - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - return $this->getPrimaryFragment() - ->hasAutomaticCapability($capability, $viewer); - } - - public function describeAutomaticCapability($capability) { - return $this->getPrimaryFragment() - ->describeAutomaticCapability($capability); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phragment/util/PhragmentPatchUtil.php phabricator-0~git20220903/phabricator/src/applications/phragment/util/PhragmentPatchUtil.php --- phabricator-0~git20200925/phabricator/src/applications/phragment/util/PhragmentPatchUtil.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phragment/util/PhragmentPatchUtil.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -<?php - -final class PhragmentPatchUtil extends Phobject { - - const EMPTY_HASH = '0000000000000000000000000000000000000000'; - - /** - * Calculate the DiffMatchPatch patch between two Phabricator files. - * - * @phutil-external-symbol class diff_match_patch - */ - public static function calculatePatch( - PhabricatorFile $old = null, - PhabricatorFile $new = null) { - - $root = dirname(phutil_get_library_root('phabricator')); - require_once $root.'/externals/diff_match_patch/diff_match_patch.php'; - - $old_hash = self::EMPTY_HASH; - $new_hash = self::EMPTY_HASH; - - if ($old !== null) { - $old_hash = $old->getContentHash(); - } - if ($new !== null) { - $new_hash = $new->getContentHash(); - } - - $old_content = ''; - $new_content = ''; - - if ($old_hash === $new_hash) { - return null; - } - - if ($old_hash !== self::EMPTY_HASH) { - $old_content = $old->loadFileData(); - } else { - $old_content = ''; - } - - if ($new_hash !== self::EMPTY_HASH) { - $new_content = $new->loadFileData(); - } else { - $new_content = ''; - } - - $dmp = new diff_match_patch(); - $dmp_patches = $dmp->patch_make($old_content, $new_content); - return $dmp->patch_toText($dmp_patches); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/phriction/application/PhabricatorPhrictionApplication.php phabricator-0~git20220903/phabricator/src/applications/phriction/application/PhabricatorPhrictionApplication.php --- phabricator-0~git20200925/phabricator/src/applications/phriction/application/PhabricatorPhrictionApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phriction/application/PhabricatorPhrictionApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -61,7 +61,7 @@ 'new/' => 'PhrictionNewController', 'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController', - 'preview/(?P<slug>.*/)' => 'PhrictionMarkupPreviewController', + 'preview/' => 'PhrictionMarkupPreviewController', 'diff/(?P<id>[1-9]\d*)/' => 'PhrictionDiffController', $this->getEditRoutePattern('document/edit/') diff -Nru phabricator-0~git20200925/phabricator/src/applications/phriction/controller/PhrictionEditController.php phabricator-0~git20220903/phabricator/src/applications/phriction/controller/PhrictionEditController.php --- phabricator-0~git20200925/phabricator/src/applications/phriction/controller/PhrictionEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phriction/controller/PhrictionEditController.php 2022-06-14 16:29:55.000000000 +0000 @@ -316,9 +316,17 @@ ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) ->setForm($form); + $preview_uri = '/phriction/preview/'; + $preview_uri = new PhutilURI( + $preview_uri, + array( + 'slug' => $document->getSlug(), + )); + $preview_uri = phutil_string_cast($preview_uri); + $preview = id(new PHUIRemarkupPreviewPanel()) ->setHeader($content->getTitle()) - ->setPreviewURI('/phriction/preview/'.$document->getSlug()) + ->setPreviewURI($preview_uri) ->setControlID('document-textarea') ->setPreviewType(PHUIRemarkupPreviewPanel::DOCUMENT); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phriction/controller/PhrictionMarkupPreviewController.php phabricator-0~git20220903/phabricator/src/applications/phriction/controller/PhrictionMarkupPreviewController.php --- phabricator-0~git20200925/phabricator/src/applications/phriction/controller/PhrictionMarkupPreviewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phriction/controller/PhrictionMarkupPreviewController.php 2022-06-14 16:29:55.000000000 +0000 @@ -3,12 +3,29 @@ final class PhrictionMarkupPreviewController extends PhabricatorController { - public function processRequest() { - $request = $this->getRequest(); - $viewer = $request->getUser(); + public function handleRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); $text = $request->getStr('text'); - $slug = $request->getURIData('slug'); + $slug = $request->getStr('slug'); + + $document = id(new PhrictionDocumentQuery()) + ->setViewer($viewer) + ->withSlugs(array($slug)) + ->needContent(true) + ->executeOne(); + if (!$document) { + $document = PhrictionDocument::initializeNewDocument( + $viewer, + $slug); + + $content = id(new PhrictionContent()) + ->setSlug($slug); + + $document + ->setPHID($document->generatePHID()) + ->attachContent($content); + } $output = PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff()) @@ -17,10 +34,7 @@ ->setContent($text), 'default', $viewer, - array( - 'phriction.isPreview' => true, - 'phriction.slug' => $slug, - )); + $document); return id(new AphrontAjaxResponse()) ->setContent($output); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phriction/markup/PhrictionRemarkupRule.php phabricator-0~git20220903/phabricator/src/applications/phriction/markup/PhrictionRemarkupRule.php --- phabricator-0~git20200925/phabricator/src/applications/phriction/markup/PhrictionRemarkupRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phriction/markup/PhrictionRemarkupRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -273,13 +273,6 @@ return null; } - // Handle content when it's a preview for the Phriction editor. - if (is_array($context)) { - if (idx($context, 'phriction.isPreview')) { - return idx($context, 'phriction.slug'); - } - } - if ($context instanceof PhrictionContent) { return $context->getSlug(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/phriction/query/PhrictionContentQuery.php phabricator-0~git20220903/phabricator/src/applications/phriction/query/PhrictionContentQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phriction/query/PhrictionContentQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phriction/query/PhrictionContentQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhrictionContent(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phriction/query/PhrictionDocumentQuery.php phabricator-0~git20220903/phabricator/src/applications/phriction/query/PhrictionDocumentQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phriction/query/PhrictionDocumentQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phriction/query/PhrictionDocumentQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -62,10 +62,6 @@ return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - public function newResultObject() { return new PhrictionDocument(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/phurl/application/PhabricatorPhurlApplication.php phabricator-0~git20220903/phabricator/src/applications/phurl/application/PhabricatorPhurlApplication.php --- phabricator-0~git20200925/phabricator/src/applications/phurl/application/PhabricatorPhurlApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phurl/application/PhabricatorPhurlApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -55,6 +55,10 @@ public function getShortRoutes() { return array( + '/status/' => 'PhabricatorStatusController', + '/favicon.ico' => 'PhabricatorFaviconController', + '/robots.txt' => 'PhabricatorRobotsShortController', + '/u/(?P<append>[^/]+)' => 'PhabricatorPhurlShortURLController', '.*' => 'PhabricatorPhurlShortURLDefaultController', ); diff -Nru phabricator-0~git20200925/phabricator/src/applications/phurl/query/PhabricatorPhurlURLQuery.php phabricator-0~git20220903/phabricator/src/applications/phurl/query/PhabricatorPhurlURLQuery.php --- phabricator-0~git20200925/phabricator/src/applications/phurl/query/PhabricatorPhurlURLQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/phurl/query/PhabricatorPhurlURLQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -50,10 +50,6 @@ return $this; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/policy/config/PhabricatorPolicyConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/policy/config/PhabricatorPolicyConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/policy/config/PhabricatorPolicyConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/policy/config/PhabricatorPolicyConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -37,7 +37,7 @@ ->setSummary(pht('Allow users to set object visibility to public.')) ->setDescription( pht( - "Phabricator allows you to set the visibility of objects (like ". + "This software allows you to set the visibility of objects (like ". "repositories and tasks) to 'Public', which means **anyone ". "on the internet can see them, without needing to log in or ". "have an account**.". @@ -59,7 +59,7 @@ ->setSummary(pht( 'Lock specific application policies so they can not be edited.')) ->setDescription(pht( - 'Phabricator has application policies which can dictate whether '. + 'This software has application policies which can dictate whether '. 'users can take certain actions, such as creating new users. '."\n\n". 'This setting allows for "locking" these policies such that no '. 'further edits can be made on a per-policy basis.')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -66,6 +66,16 @@ 'description.conduit' => pht('Change the join policy of the object.'), 'edit' => 'join', ), + PhabricatorTransactions::TYPE_INTERACT_POLICY => array( + 'key' => 'policy.interact', + 'aliases' => array('interact'), + 'capability' => PhabricatorPolicyCapability::CAN_INTERACT, + 'label' => pht('Interact Policy'), + 'description' => pht('Controls who can interact with the object.'), + 'description.conduit' + => pht('Change the interaction policy of the object.'), + 'edit' => 'interact', + ), ); if ($object instanceof PhabricatorPolicyCodexInterface) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/policy/filter/PhabricatorPolicyFilterSet.php phabricator-0~git20220903/phabricator/src/applications/policy/filter/PhabricatorPolicyFilterSet.php --- phabricator-0~git20200925/phabricator/src/applications/policy/filter/PhabricatorPolicyFilterSet.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/policy/filter/PhabricatorPolicyFilterSet.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,167 @@ +<?php + +final class PhabricatorPolicyFilterSet + extends Phobject { + + private $users = array(); + private $objects = array(); + + private $capabilities = array(); + private $queue = array(); + private $results = array(); + + public function addCapability( + PhabricatorUser $user, + PhabricatorPolicyInterface $object, + $capability) { + + $user_key = $this->getUserKey($user); + $this->users[$user_key] = $user; + + $object_key = $this->getObjectKey($object); + $this->objects[$object_key] = $object; + + if (!isset($this->capabilities[$capability][$user_key][$object_key])) { + $this->capabilities[$capability][$user_key][$object_key] = true; + $this->queue[$capability][$user_key][$object_key] = true; + } + + return $this; + } + + public function hasCapability( + PhabricatorUser $user, + PhabricatorPolicyInterface $object, + $capability) { + + $user_key = $this->getUserKey($user); + $this->users[$user_key] = $user; + + $object_key = $this->getObjectKey($object); + $this->objects[$object_key] = $object; + + if (!isset($this->capabilities[$capability][$user_key][$object_key])) { + throw new Exception( + pht( + 'Capability "%s" for user "%s" on object "%s" is being resolved, '. + 'but was never queued with "addCapability()".', + $capability, + $user_key, + $object_key)); + } + + if (!isset($this->results[$capability][$user_key][$object_key])) { + $this->resolveCapabilities(); + } + + return $this->results[$capability][$user_key][$object_key]; + } + + private function getUserKey(PhabricatorUser $user) { + return $user->getCacheFragment(); + } + + private function getObjectKey(PhabricatorPolicyInterface $object) { + $object_phid = $object->getPHID(); + + if (!$object_phid) { + throw new Exception( + pht( + 'Unable to perform capability tests on an object (of class "%s") '. + 'with no PHID.', + get_class($object))); + } + + return $object_phid; + } + + private function resolveCapabilities() { + + // This class is primarily used to test if a list of users (like + // subscribers) can see a single object. It is not structured in a way + // that makes this particularly efficient, and performance would probably + // be improved if filtering supported this use case more narrowly. + + foreach ($this->queue as $capability => $user_map) { + foreach ($user_map as $user_key => $object_map) { + $user = $this->users[$user_key]; + $objects = array_select_keys($this->objects, array_keys($object_map)); + + $filter = id(new PhabricatorPolicyFilter()) + ->setViewer($user) + ->requireCapabilities(array($capability)); + $results = $filter->apply($objects); + + foreach ($object_map as $object_key => $object) { + $has_capability = (bool)isset($results[$object_key]); + $this->results[$capability][$user_key][$object_key] = $has_capability; + } + } + } + + $this->queue = array(); + } + + public static function loadHandleViewCapabilities( + $viewer, + $handles, + array $objects) { + + $capabilities = array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + + assert_instances_of($objects, 'PhabricatorPolicyInterface'); + + if (!$objects) { + return; + } + + $viewer_map = array(); + foreach ($handles as $handle_key => $handle) { + if (!$handle->hasCapabilities()) { + continue; + } + $viewer_map[$handle->getPHID()] = $handle_key; + } + + if (!$viewer_map) { + return; + } + + $users = id(new PhabricatorPeopleQuery()) + ->setViewer($viewer) + ->withPHIDs(array_keys($viewer_map)) + ->execute(); + $users = mpull($users, null, 'getPHID'); + + $filter_set = new self(); + + foreach ($users as $user_phid => $user) { + foreach ($objects as $object) { + foreach ($capabilities as $capability) { + $filter_set->addCapability($user, $object, $capability); + } + } + } + + foreach ($users as $user_phid => $user) { + $handle_key = $viewer_map[$user_phid]; + $handle = $handles[$handle_key]; + foreach ($objects as $object) { + foreach ($capabilities as $capability) { + $has_capability = $filter_set->hasCapability( + $user, + $object, + $capability); + + $handle->attachCapability( + $object, + $capability, + $has_capability); + } + } + } + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/policy/management/PhabricatorPolicyManagementUnlockWorkflow.php phabricator-0~git20220903/phabricator/src/applications/policy/management/PhabricatorPolicyManagementUnlockWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/policy/management/PhabricatorPolicyManagementUnlockWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/policy/management/PhabricatorPolicyManagementUnlockWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,9 +8,16 @@ ->setName('unlock') ->setSynopsis( pht( - 'Unlock an object which has policies that prevent it from being '. - 'viewed or edited.')) - ->setExamples('**unlock** --view __user__ __object__') + 'Unlock one or more objects by changing their view policies, edit '. + 'policies, or owners.')) + ->setHelp( + pht( + 'Identify each __object__ by passing an object name '. + '(like "T123") or a PHID (like "PHID-ABCD-1234...").'. + "\n\n". + 'Not every type of object has an editable view policy, edit '. + 'policy, or owner, so not all modes will work with all objects. ')) + ->setExamples('**unlock** --view __user__ __object__ ...') ->setArguments( array( array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/policy/query/PhabricatorPolicyQuery.php phabricator-0~git20220903/phabricator/src/applications/policy/query/PhabricatorPolicyQuery.php --- phabricator-0~git20200925/phabricator/src/applications/policy/query/PhabricatorPolicyQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/policy/query/PhabricatorPolicyQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -290,6 +290,10 @@ } public static function isSpecialPolicy($identifier) { + if ($identifier === null) { + return true; + } + if (self::isObjectPolicy($identifier)) { return true; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/policy/storage/PhabricatorPolicy.php phabricator-0~git20220903/phabricator/src/applications/policy/storage/PhabricatorPolicy.php --- phabricator-0~git20200925/phabricator/src/applications/policy/storage/PhabricatorPolicy.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/policy/storage/PhabricatorPolicy.php 2022-06-14 16:29:55.000000000 +0000 @@ -248,7 +248,7 @@ case PhabricatorPolicies::POLICY_PUBLIC: return pht( 'This object is public and can be viewed by anyone, even if they '. - 'do not have a Phabricator account.'); + 'do not have an account on this server.'); case PhabricatorPolicies::POLICY_USER: return pht('Logged in users can take this action.'); case PhabricatorPolicies::POLICY_ADMIN: @@ -417,12 +417,23 @@ PhabricatorPolicies::POLICY_NOONE => 1, ); - $this_strength = idx($strengths, $this->getPHID(), 0); - $other_strength = idx($strengths, $other->getPHID(), 0); + $this_strength = idx($strengths, $this_policy, 0); + $other_strength = idx($strengths, $other_policy, 0); return ($this_strength > $other_strength); } + public function isStrongerThanOrEqualTo(PhabricatorPolicy $other) { + $this_policy = $this->getPHID(); + $other_policy = $other->getPHID(); + + if ($this_policy === $other_policy) { + return true; + } + + return $this->isStrongerThan($other); + } + public function isValidPolicyForEdit() { return $this->getType() !== PhabricatorPolicyType::TYPE_MASKED; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/ponder/query/PonderAnswerQuery.php phabricator-0~git20220903/phabricator/src/applications/ponder/query/PonderAnswerQuery.php --- phabricator-0~git20200925/phabricator/src/applications/ponder/query/PonderAnswerQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/ponder/query/PonderAnswerQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -59,10 +59,6 @@ return new PonderAnswer(); } - protected function loadPage() { - return $this->loadStandardPage(new PonderAnswer()); - } - protected function willFilterPage(array $answers) { $questions = id(new PonderQuestionQuery()) ->setViewer($this->getViewer()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/ponder/query/PonderQuestionQuery.php phabricator-0~git20220903/phabricator/src/applications/ponder/query/PonderQuestionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/ponder/query/PonderQuestionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/ponder/query/PonderQuestionQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -86,10 +86,6 @@ return new PonderQuestion(); } - protected function loadPage() { - return $this->loadStandardPage(new PonderQuestion()); - } - protected function willFilterPage(array $questions) { $phids = mpull($questions, 'getPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -73,27 +73,87 @@ $project->openTransaction(); - // Delete any existing materialized member edges. - queryfx( + // Copy current member edges to create new materialized edges. + + // See T13596. Avoid executing this as an "INSERT ... SELECT" to reduce + // the required level of table locking. Since we're decomposing it into + // "SELECT" + "INSERT" anyway, we can also compute exactly which rows + // need to be modified. + + $have_rows = queryfx_all( $conn_w, - 'DELETE FROM %T WHERE src = %s AND type = %s', + 'SELECT dst FROM %T + WHERE src = %s AND type = %d', PhabricatorEdgeConfig::TABLE_NAME_EDGE, $project_phid, $material_type); - // Copy current member edges to create new materialized edges. - queryfx( + $want_rows = queryfx_all( $conn_w, - 'INSERT IGNORE INTO %T (src, type, dst, dateCreated, seq) - SELECT %s, %d, dst, dateCreated, seq FROM %T + 'SELECT dst, dateCreated, seq FROM %T WHERE src IN (%Ls) AND type = %d', PhabricatorEdgeConfig::TABLE_NAME_EDGE, - $project_phid, - $material_type, - PhabricatorEdgeConfig::TABLE_NAME_EDGE, $source_phids, $member_type); + $have_phids = ipull($have_rows, 'dst', 'dst'); + $want_phids = ipull($want_rows, null, 'dst'); + + $rem_phids = array_diff_key($have_phids, $want_phids); + $rem_phids = array_keys($rem_phids); + + $add_phids = array_diff_key($want_phids, $have_phids); + $add_phids = array_keys($add_phids); + + $rem_sql = array(); + foreach ($rem_phids as $rem_phid) { + $rem_sql[] = qsprintf( + $conn_w, + '%s', + $rem_phid); + } + + $add_sql = array(); + foreach ($add_phids as $add_phid) { + $add_row = $want_phids[$add_phid]; + $add_sql[] = qsprintf( + $conn_w, + '(%s, %d, %s, %d, %d)', + $project_phid, + $material_type, + $add_row['dst'], + $add_row['dateCreated'], + $add_row['seq']); + } + + // Remove materialized members who are no longer project members. + + if ($rem_sql) { + foreach (PhabricatorLiskDAO::chunkSQL($rem_sql) as $sql_chunk) { + queryfx( + $conn_w, + 'DELETE FROM %T + WHERE src = %s AND type = %s AND dst IN (%LQ)', + PhabricatorEdgeConfig::TABLE_NAME_EDGE, + $project_phid, + $material_type, + $sql_chunk); + } + } + + // Add project members who are not yet materialized members. + + if ($add_sql) { + foreach (PhabricatorLiskDAO::chunkSQL($add_sql) as $sql_chunk) { + queryfx( + $conn_w, + 'INSERT IGNORE INTO %T (src, type, dst, dateCreated, seq) + VALUES %LQ', + PhabricatorEdgeConfig::TABLE_NAME_EDGE, + $sql_chunk); + } + } + // Update the hasSubprojects flag. queryfx( $conn_w, diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectColumnPositionQuery.php phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectColumnPositionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectColumnPositionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectColumnPositionQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhabricatorProjectColumnPosition(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectColumnQuery.php phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectColumnQuery.php --- phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectColumnQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectColumnQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -56,10 +56,6 @@ return new PhabricatorProjectColumn(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { $projects = array(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectQuery.php phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectQuery.php --- phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -236,10 +236,6 @@ } } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $projects) { $ancestor_paths = array(); foreach ($projects as $project) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectTriggerQuery.php phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectTriggerQuery.php --- phabricator-0~git20200925/phabricator/src/applications/project/query/PhabricatorProjectTriggerQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/query/PhabricatorProjectTriggerQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,10 +35,6 @@ return new PhabricatorProjectTrigger(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/storage/PhabricatorProject.php phabricator-0~git20220903/phabricator/src/applications/project/storage/PhabricatorProject.php --- phabricator-0~git20200925/phabricator/src/applications/project/storage/PhabricatorProject.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/storage/PhabricatorProject.php 2022-06-14 16:29:55.000000000 +0000 @@ -407,11 +407,13 @@ $this->setMailKey(Filesystem::readRandomCharacters(20)); } - if (!strlen($this->getPHID())) { + $phid = $this->getPHID(); + if ($phid === null || $phid === '') { $this->setPHID($this->generatePHID()); } - if (!strlen($this->getProjectPathKey())) { + $path_key = $this->getProjectPathKey(); + if ($path_key === null || $path_key === '') { $hash = PhabricatorHash::digestForIndex($this->getPHID()); $hash = substr($hash, 0, 4); $this->setProjectPathKey($hash); diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php phabricator-0~git20220903/phabricator/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -1435,7 +1435,7 @@ $task = ManiphestTask::initializeNewTask($viewer); - if (!strlen($name)) { + if ($name === null || $name === '') { $name = pht('Test Task'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/project/xaction/PhabricatorProjectImageTransaction.php phabricator-0~git20220903/phabricator/src/applications/project/xaction/PhabricatorProjectImageTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/project/xaction/PhabricatorProjectImageTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/project/xaction/PhabricatorProjectImageTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -13,34 +13,6 @@ $object->setProfileImagePHID($value); } - public function applyExternalEffects($object, $value) { - $old = $this->getOldValue(); - $new = $value; - $all = array(); - if ($old) { - $all[] = $old; - } - if ($new) { - $all[] = $new; - } - - $files = id(new PhabricatorFileQuery()) - ->setViewer($this->getActor()) - ->withPHIDs($all) - ->execute(); - $files = mpull($files, null, 'getPHID'); - - $old_file = idx($files, $old); - if ($old_file) { - $old_file->detachFromObject($object->getPHID()); - } - - $new_file = idx($files, $new); - if ($new_file) { - $new_file->attachToObject($object->getPHID()); - } - } - public function getTitle() { $old = $this->getOldValue(); $new = $this->getNewValue(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/application/PhabricatorReleephApplication.php phabricator-0~git20220903/phabricator/src/applications/releeph/application/PhabricatorReleephApplication.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/application/PhabricatorReleephApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/application/PhabricatorReleephApplication.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -<?php - -final class PhabricatorReleephApplication extends PhabricatorApplication { - - public function getName() { - return pht('Releeph'); - } - - public function getShortDescription() { - return pht('Pull Requests'); - } - - public function getBaseURI() { - return '/releeph/'; - } - - public function getIcon() { - return 'fa-flag-checkered'; - } - - public function getApplicationGroup() { - return self::GROUP_UTILITIES; - } - - public function isPrototype() { - return true; - } - - public function getRoutes() { - return array( - '/Y(?P<requestID>[1-9]\d*)' => 'ReleephRequestViewController', - - // TODO: Remove these older routes eventually. - '/RQ(?P<requestID>[1-9]\d*)' => 'ReleephRequestViewController', - '/releeph/request/(?P<requestID>[1-9]\d*)/' - => 'ReleephRequestViewController', - - '/releeph/' => array( - '' => 'ReleephProductListController', - '(?:product|project)/' => array( - '(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephProductListController', - 'create/' => 'ReleephProductCreateController', - '(?P<projectID>[1-9]\d*)/' => array( - '(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephProductViewController', - 'edit/' => 'ReleephProductEditController', - 'cutbranch/' => 'ReleephBranchCreateController', - 'action/(?P<action>.+)/' => 'ReleephProductActionController', - 'history/' => 'ReleephProductHistoryController', - ), - ), - - 'branch/' => array( - 'edit/(?P<branchID>[1-9]\d*)/' - => 'ReleephBranchEditController', - '(?P<action>close|re-open)/(?P<branchID>[1-9]\d*)/' - => 'ReleephBranchAccessController', - 'preview/' => 'ReleephBranchNamePreviewController', - '(?P<branchID>[1-9]\d*)/' => array( - 'history/' => 'ReleephBranchHistoryController', - '(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephBranchViewController', - ), - 'pull/(?P<branchID>[1-9]\d*)/' - => 'ReleephRequestEditController', - ), - - 'request/' => array( - 'create/' => 'ReleephRequestEditController', - 'differentialcreate/' => array( - 'D(?P<diffRevID>[1-9]\d*)' => - 'ReleephRequestDifferentialCreateController', - ), - 'edit/(?P<requestID>[1-9]\d*)/' - => 'ReleephRequestEditController', - 'action/(?P<action>.+)/(?P<requestID>[1-9]\d*)/' - => 'ReleephRequestActionController', - 'typeahead/' => - 'ReleephRequestTypeaheadController', - 'comment/(?P<requestID>[1-9]\d*)/' - => 'ReleephRequestCommentController', - ), - ), - ); - } - - public function getMailCommandObjects() { - // TODO: Pull requests don't implement any interfaces which give them - // meaningful commands, so don't expose ReleephRequest here for now. - // Once we add relevant commands, return it here. - return array(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinderException.php phabricator-0~git20220903/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinderException.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinderException.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinderException.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -<?php - -final class ReleephCommitFinderException extends Exception {} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinder.php phabricator-0~git20220903/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinder.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinder.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/commitfinder/ReleephCommitFinder.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -<?php - -final class ReleephCommitFinder extends Phobject { - - private $releephProject; - private $user; - private $objectPHID; - - public function setUser(PhabricatorUser $user) { - $this->user = $user; - return $this; - } - public function getUser() { - return $this->user; - } - - public function setReleephProject(ReleephProject $rp) { - $this->releephProject = $rp; - return $this; - } - - public function getRequestedObjectPHID() { - return $this->objectPHID; - } - - public function fromPartial($partial_string) { - $this->objectPHID = null; - - // Look for diffs - $matches = array(); - if (preg_match('/^D([1-9]\d*)$/', $partial_string, $matches)) { - $diff_id = $matches[1]; - $diff_rev = id(new DifferentialRevisionQuery()) - ->setViewer($this->getUser()) - ->withIDs(array($diff_id)) - ->needCommitPHIDs(true) - ->executeOne(); - if (!$diff_rev) { - throw new ReleephCommitFinderException( - pht( - '%s does not refer to an existing diff.', - $partial_string)); - } - $commit_phids = $diff_rev->getCommitPHIDs(); - - if (!$commit_phids) { - throw new ReleephCommitFinderException( - pht( - '%s has no commits associated with it yet.', - $partial_string)); - } - - $this->objectPHID = $diff_rev->getPHID(); - - $commits = id(new DiffusionCommitQuery()) - ->setViewer($this->getUser()) - ->withPHIDs($commit_phids) - ->execute(); - $commits = msort($commits, 'getEpoch'); - return head($commits); - } - - // Look for a raw commit number, or r<callsign><commit-number>. - $repository = $this->releephProject->getRepository(); - $dr_data = null; - $matches = array(); - if (preg_match('/^r(?P<callsign>[A-Z]+)(?P<commit>\w+)$/', - $partial_string, $matches)) { - $callsign = $matches['callsign']; - if ($callsign != $repository->getCallsign()) { - throw new ReleephCommitFinderException( - pht( - '%s is in a different repository to this Releeph project (%s).', - $partial_string, - $repository->getCallsign())); - } else { - $dr_data = $matches; - } - } else { - $dr_data = array( - 'callsign' => $repository->getCallsign(), - 'commit' => $partial_string, - ); - } - - try { - $dr_data['user'] = $this->getUser(); - $dr = DiffusionRequest::newFromDictionary($dr_data); - } catch (Exception $ex) { - $message = pht( - 'No commit matches %s: %s', - $partial_string, - $ex->getMessage()); - throw new ReleephCommitFinderException($message); - } - - $phabricator_repository_commit = $dr->loadCommit(); - - if (!$phabricator_repository_commit) { - throw new ReleephCommitFinderException( - pht( - "The commit %s doesn't exist in this repository.", - $partial_string)); - } - - // When requesting a single commit, if it has an associated review we - // imply the review was requested instead. This is always correct for now - // and consistent with the older behavior, although it might not be the - // right rule in the future. - $phids = PhabricatorEdgeQuery::loadDestinationPHIDs( - $phabricator_repository_commit->getPHID(), - DiffusionCommitHasRevisionEdgeType::EDGECONST); - if ($phids) { - $this->objectPHID = head($phids); - } - - return $phabricator_repository_commit; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -<?php - -abstract class ReleephConduitAPIMethod extends ConduitAPIMethod { - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodStatusDescription() { - return pht('All Releeph methods are subject to abrupt change.'); - } - - final public function getApplication() { - return PhabricatorApplication::getByClass('PhabricatorReleephApplication'); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -<?php - -final class ReleephGetBranchesConduitAPIMethod extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releeph.getbranches'; - } - - public function getMethodDescription() { - return pht('Return information about all active Releeph branches.'); - } - - protected function defineParamTypes() { - return array( - ); - } - - protected function defineReturnType() { - return 'nonempty list<dict<string, wild>>'; - } - - protected function execute(ConduitAPIRequest $request) { - $results = array(); - - $projects = id(new ReleephProductQuery()) - ->setViewer($request->getUser()) - ->withActive(1) - ->execute(); - - foreach ($projects as $project) { - $repository = $project->getRepository(); - - $branches = id(new ReleephBranch())->loadAllWhere( - 'releephProjectID = %d AND isActive = 1', - $project->getID()); - - foreach ($branches as $branch) { - $full_branch_name = $branch->getName(); - - $cut_point_commit = id(new PhabricatorRepositoryCommit())->loadOneWhere( - 'phid = %s', - $branch->getCutPointCommitPHID()); - - $results[] = array( - 'project' => $project->getName(), - 'repository' => $repository->getCallsign(), - 'branch' => $branch->getBasename(), - 'fullBranchName' => $full_branch_name, - 'symbolicName' => $branch->getSymbolicName(), - 'cutPoint' => $cut_point_commit->getCommitIdentifier(), - ); - } - } - - return $results; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -<?php - -final class ReleephQueryBranchesConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releeph.querybranches'; - } - - public function getMethodDescription() { - return pht('Query information about Releeph branches.'); - } - - protected function defineParamTypes() { - return array( - 'ids' => 'optional list<id>', - 'phids' => 'optional list<phid>', - 'productPHIDs' => 'optional list<phid>', - ) + $this->getPagerParamTypes(); - } - - protected function defineReturnType() { - return 'query-results'; - } - - protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); - - $query = id(new ReleephBranchQuery()) - ->setViewer($viewer); - - $ids = $request->getValue('ids'); - if ($ids !== null) { - $query->withIDs($ids); - } - - $phids = $request->getValue('phids'); - if ($phids !== null) { - $query->withPHIDs($phids); - } - - $product_phids = $request->getValue('productPHIDs'); - if ($product_phids !== null) { - $query->withProductPHIDs($product_phids); - } - - $pager = $this->newPager($request); - $branches = $query->executeWithCursorPager($pager); - - $data = array(); - foreach ($branches as $branch) { - $id = $branch->getID(); - - $uri = '/releeph/branch/'.$id.'/'; - $uri = PhabricatorEnv::getProductionURI($uri); - - $data[] = array( - 'id' => $id, - 'phid' => $branch->getPHID(), - 'uri' => $uri, - 'name' => $branch->getName(), - 'productPHID' => $branch->getProduct()->getPHID(), - ); - } - - return $this->addPagerResults( - array( - 'data' => $data, - ), - $pager); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -<?php - -final class ReleephQueryProductsConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releeph.queryproducts'; - } - - public function getMethodDescription() { - return pht('Query information about Releeph products.'); - } - - protected function defineParamTypes() { - return array( - 'ids' => 'optional list<id>', - 'phids' => 'optional list<phid>', - 'repositoryPHIDs' => 'optional list<phid>', - 'isActive' => 'optional bool', - ) + $this->getPagerParamTypes(); - } - - protected function defineReturnType() { - return 'query-results'; - } - - protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); - - $query = id(new ReleephProductQuery()) - ->setViewer($viewer); - - $ids = $request->getValue('ids'); - if ($ids !== null) { - $query->withIDs($ids); - } - - $phids = $request->getValue('phids'); - if ($phids !== null) { - $query->withPHIDs($phids); - } - - $repository_phids = $request->getValue('repositoryPHIDs'); - if ($repository_phids !== null) { - $query->withRepositoryPHIDs($repository_phids); - } - - $is_active = $request->getValue('isActive'); - if ($is_active !== null) { - $query->withActive($is_active); - } - - $pager = $this->newPager($request); - $products = $query->executeWithCursorPager($pager); - - $data = array(); - foreach ($products as $product) { - $id = $product->getID(); - - $uri = '/releeph/product/'.$id.'/'; - $uri = PhabricatorEnv::getProductionURI($uri); - - $data[] = array( - 'id' => $id, - 'phid' => $product->getPHID(), - 'uri' => $uri, - 'name' => $product->getName(), - 'isActive' => (bool)$product->getIsActive(), - 'repositoryPHID' => $product->getRepositoryPHID(), - ); - } - - return $this->addPagerResults( - array( - 'data' => $data, - ), - $pager); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -<?php - -final class ReleephQueryRequestsConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releeph.queryrequests'; - } - - public function getMethodDescription() { - return pht( - 'Return information about all Releeph requests linked to the given ids.'); - } - - protected function defineParamTypes() { - return array( - 'revisionPHIDs' => 'optional list<phid>', - 'requestedCommitPHIDs' => 'optional list<phid>', - ); - } - - protected function defineReturnType() { - return 'dict<string, wild>'; - } - - protected function execute(ConduitAPIRequest $conduit_request) { - $revision_phids = $conduit_request->getValue('revisionPHIDs'); - $requested_commit_phids = - $conduit_request->getValue('requestedCommitPHIDs'); - $result = array(); - - if (!$revision_phids && !$requested_commit_phids) { - return $result; - } - - $query = new ReleephRequestQuery(); - $query->setViewer($conduit_request->getUser()); - - if ($revision_phids) { - $query->withRequestedObjectPHIDs($revision_phids); - } else if ($requested_commit_phids) { - $query->withRequestedCommitPHIDs($requested_commit_phids); - } - - $releeph_requests = $query->execute(); - - foreach ($releeph_requests as $releeph_request) { - $branch = $releeph_request->getBranch(); - - $request_commit_phid = $releeph_request->getRequestCommitPHID(); - - $object = $releeph_request->getRequestedObject(); - if ($object instanceof DifferentialRevision) { - $object_phid = $object->getPHID(); - } else { - $object_phid = null; - } - - $status = $releeph_request->getStatus(); - $status_name = ReleephRequestStatus::getStatusDescriptionFor($status); - $url = PhabricatorEnv::getProductionURI('/RQ'.$releeph_request->getID()); - - $result[] = array( - 'branchBasename' => $branch->getBasename(), - 'branchSymbolic' => $branch->getSymbolicName(), - 'requestID' => $releeph_request->getID(), - 'revisionPHID' => $object_phid, - 'status' => $status, - 'status_name' => $status_name, - 'url' => $url, - ); - } - - return $result; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/ReleephRequestConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -<?php - -final class ReleephRequestConduitAPIMethod extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releeph.request'; - } - - public function getMethodDescription() { - return pht('Request a commit or diff to be picked to a branch.'); - } - - protected function defineParamTypes() { - return array( - 'branchPHID' => 'required string', - 'things' => 'required list<string>', - 'fields' => 'dict<string, string>', - ); - } - - protected function defineReturnType() { - return 'dict<string, wild>'; - } - - protected function defineErrorTypes() { - return array( - 'ERR_BRANCH' => pht('Unknown Releeph branch.'), - 'ERR_FIELD_PARSE' => pht('Unable to parse a Releeph field.'), - ); - } - - protected function execute(ConduitAPIRequest $request) { - $user = $request->getUser(); - - $viewer_handle = id(new PhabricatorHandleQuery()) - ->setViewer($user) - ->withPHIDs(array($user->getPHID())) - ->executeOne(); - - $branch_phid = $request->getValue('branchPHID'); - $releeph_branch = id(new ReleephBranchQuery()) - ->setViewer($user) - ->withPHIDs(array($branch_phid)) - ->executeOne(); - - if (!$releeph_branch) { - throw id(new ConduitException('ERR_BRANCH'))->setErrorDescription( - pht( - 'No %s found with PHID %s!', - 'ReleephBranch', - $branch_phid)); - } - - $releeph_project = $releeph_branch->getProduct(); - - // Find the requested commit identifiers - $requested_commits = array(); - $requested_object_phids = array(); - $things = $request->getValue('things'); - $finder = id(new ReleephCommitFinder()) - ->setUser($user) - ->setReleephProject($releeph_project); - foreach ($things as $thing) { - try { - $requested_commits[$thing] = $finder->fromPartial($thing); - $object_phid = $finder->getRequestedObjectPHID(); - if (!$object_phid) { - $object_phid = $requested_commits[$thing]->getPHID(); - } - $requested_object_phids[$thing] = $object_phid; - } catch (ReleephCommitFinderException $ex) { - throw id(new ConduitException('ERR_NO_MATCHES')) - ->setErrorDescription($ex->getMessage()); - } - } - $requested_commit_phids = mpull($requested_commits, 'getPHID'); - - // Find any existing requests that clash on the commit id, for this branch - $existing_releeph_requests = id(new ReleephRequest())->loadAllWhere( - 'requestCommitPHID IN (%Ls) AND branchID = %d', - $requested_commit_phids, - $releeph_branch->getID()); - $existing_releeph_requests = mpull( - $existing_releeph_requests, - null, - 'getRequestCommitPHID'); - - $selector = $releeph_project->getReleephFieldSelector(); - $fields = $selector->getFieldSpecifications(); - foreach ($fields as $field) { - $field - ->setReleephProject($releeph_project) - ->setReleephBranch($releeph_branch); - } - - $results = array(); - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($user) - ->withPHIDs($requested_commit_phids) - ->execute(); - foreach ($requested_commits as $thing => $commit) { - $phid = $commit->getPHID(); - $name = id($handles[$phid])->getName(); - - $releeph_request = null; - - $existing_releeph_request = idx($existing_releeph_requests, $phid); - if ($existing_releeph_request) { - $releeph_request = $existing_releeph_request; - } else { - $releeph_request = id(new ReleephRequest()) - ->setRequestUserPHID($user->getPHID()) - ->setBranchID($releeph_branch->getID()) - ->setInBranch(0) - ->setRequestedObjectPHID($requested_object_phids[$thing]); - - $xactions = array(); - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_REQUEST) - ->setNewValue($commit->getPHID()); - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT) - ->setMetadataValue('userPHID', $user->getPHID()) - ->setMetadataValue( - 'isAuthoritative', - $releeph_project->isAuthoritative($user)) - ->setNewValue(ReleephRequest::INTENT_WANT); - - foreach ($fields as $field) { - if (!$field->isEditable()) { - continue; - } - $field->setReleephRequest($releeph_request); - try { - $field->setValueFromConduitAPIRequest($request); - } catch (ReleephFieldParseException $ex) { - throw id(new ConduitException('ERR_FIELD_PARSE')) - ->setErrorDescription($ex->getMessage()); - } - } - - $editor = id(new ReleephRequestTransactionalEditor()) - ->setActor($user) - ->setContinueOnNoEffect(true) - ->setContentSource($request->newContentSource()); - - $editor->applyTransactions($releeph_request, $xactions); - } - - $url = PhabricatorEnv::getProductionURI('/Y'.$releeph_request->getID()); - $results[$thing] = array( - 'thing' => $thing, - 'branch' => $releeph_branch->getDisplayNameWithDetail(), - 'commitName' => $name, - 'commitID' => $commit->getCommitIdentifier(), - 'url' => $url, - 'requestID' => $releeph_request->getID(), - 'requestor' => $viewer_handle->getName(), - 'requestTime' => $releeph_request->getDateCreated(), - 'existing' => $existing_releeph_request !== null, - ); - } - - return $results; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -<?php - -final class ReleephWorkCanPushConduitAPIMethod extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releephwork.canpush'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht('Return whether the conduit user is allowed to push.'); - } - - protected function defineParamTypes() { - return array( - 'projectPHID' => 'required string', - ); - } - - protected function defineReturnType() { - return 'bool'; - } - - protected function execute(ConduitAPIRequest $request) { - $releeph_project = id(new ReleephProject()) - ->loadOneWhere('phid = %s', $request->getValue('projectPHID')); - $user = $request->getUser(); - return $releeph_project->isAuthoritative($user); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -<?php - -final class ReleephWorkGetAuthorInfoConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releephwork.getauthorinfo'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht('Return a string to use as the VCS author.'); - } - - protected function defineParamTypes() { - return array( - 'userPHID' => 'required string', - 'vcsType' => 'required string', - ); - } - - protected function defineReturnType() { - return 'nonempty string'; - } - - protected function execute(ConduitAPIRequest $request) { - $user = id(new PhabricatorUser()) - ->loadOneWhere('phid = %s', $request->getValue('userPHID')); - - $email = $user->loadPrimaryEmailAddress(); - if (is_numeric($email)) { - $email = $user->getUserName().'@fb.com'; - } - - return sprintf( - '%s <%s>', - $user->getRealName(), - $email); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -<?php - -final class ReleephWorkGetBranchCommitMessageConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releephwork.getbranchcommitmessage'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht('Get a commit message for committing a Releeph branch.'); - } - - protected function defineParamTypes() { - return array( - 'branchPHID' => 'required string', - ); - } - - protected function defineReturnType() { - return 'nonempty string'; - } - - protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); - - $branch = id(new ReleephBranchQuery()) - ->setViewer($viewer) - ->withPHIDs(array($request->getValue('branchPHID'))) - ->executeOne(); - - $project = $branch->getProduct(); - - $creator_phid = $branch->getCreatedByUserPHID(); - $cut_phid = $branch->getCutPointCommitPHID(); - - $phids = array( - $branch->getPHID(), - $project->getPHID(), - $creator_phid, - $cut_phid, - ); - - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($request->getUser()) - ->withPHIDs($phids) - ->execute(); - - $h_branch = $handles[$branch->getPHID()]; - $h_project = $handles[$project->getPHID()]; - - // Not as customizable as a ReleephRequest's commit message. It doesn't - // really need to be. - // TODO: Yes it does, see FB-specific stuff below. - $commit_message = array(); - $commit_message[] = $h_branch->getFullName(); - $commit_message[] = $h_branch->getURI(); - - $commit_message[] = pht('Cut Point: %s', $handles[$cut_phid]->getName()); - - $cut_point_pr_commit = id(new PhabricatorRepositoryCommit()) - ->loadOneWhere('phid = %s', $cut_phid); - $cut_point_commit_date = strftime( - '%Y-%m-%d %H:%M:%S%z', - $cut_point_pr_commit->getEpoch()); - $commit_message[] = pht('Cut Point Date: %s', $cut_point_commit_date); - - $commit_message[] = pht( - 'Created By: %s', - $handles[$creator_phid]->getName()); - - $project_uri = $project->getURI(); - $commit_message[] = pht( - 'Project: %s', - $h_project->getName().' '.$project_uri); - - /** - * Required for 090-limit_new_branch_creations.sh in - * admin/scripts/git/hosting/hooks/update.d (in the E repo): - * - * http://fburl.com/2372545 - * - * The commit message must have a line saying: - * - * @new-branch: <branch-name> - * - */ - $repo = $project->getRepository(); - switch ($repo->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $commit_message[] = sprintf( - '@new-branch: %s', - $branch->getName()); - break; - } - - return implode("\n\n", $commit_message); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -<?php - -final class ReleephWorkGetBranchConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releephwork.getbranch'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht('Return information to help checkout / cut a Releeph branch.'); - } - - protected function defineParamTypes() { - return array( - 'branchPHID' => 'required string', - ); - } - - protected function defineReturnType() { - return 'dict<string, wild>'; - } - - protected function execute(ConduitAPIRequest $request) { - $branch = id(new ReleephBranchQuery()) - ->setViewer($request->getUser()) - ->withPHIDs(array($request->getValue('branchPHID'))) - ->needCutPointCommits(true) - ->executeOne(); - - $cut_phid = $branch->getCutPointCommitPHID(); - $phids = array($cut_phid); - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($request->getUser()) - ->withPHIDs($phids) - ->execute(); - - $project = $branch->getProject(); - $repo = $project->getRepository(); - $commit = $branch->getCutPointCommit(); - - return array( - 'branchName' => $branch->getName(), - 'branchPHID' => $branch->getPHID(), - 'vcsType' => $repo->getVersionControlSystem(), - 'cutCommitID' => $commit->getCommitIdentifier(), - 'cutCommitName' => $handles[$cut_phid]->getName(), - 'creatorPHID' => $branch->getCreatedByUserPHID(), - 'trunk' => $project->getTrunkBranch(), - ); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -<?php - -final class ReleephWorkGetCommitMessageConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releephwork.getcommitmessage'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht( - 'Get commit message components for building a %s commit message.', - 'ReleephRequest'); - } - - protected function defineParamTypes() { - $action_const = $this->formatStringConstants(array('pick', 'revert')); - - return array( - 'requestPHID' => 'required string', - 'action' => 'required '.$action_const, - ); - } - - protected function defineReturnType() { - return 'dict<string, string>'; - } - - protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); - - $releeph_request = id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withPHIDs(array($request->getValue('requestPHID'))) - ->executeOne(); - - $action = $request->getValue('action'); - - $title = $releeph_request->getSummaryForDisplay(); - - $commit_message = array(); - - $branch = $releeph_request->getBranch(); - $project = $branch->getProduct(); - - $selector = $project->getReleephFieldSelector(); - $fields = $selector->getFieldSpecifications(); - $fields = $selector->sortFieldsForCommitMessage($fields); - - foreach ($fields as $field) { - $field - ->setUser($request->getUser()) - ->setReleephProject($project) - ->setReleephBranch($branch) - ->setReleephRequest($releeph_request); - - $label = null; - $value = null; - - switch ($action) { - case 'pick': - if ($field->shouldAppearOnCommitMessage()) { - $label = $field->renderLabelForCommitMessage(); - $value = $field->renderValueForCommitMessage(); - } - break; - - case 'revert': - if ($field->shouldAppearOnRevertMessage()) { - $label = $field->renderLabelForRevertMessage(); - $value = $field->renderValueForRevertMessage(); - } - break; - } - - if ($label && $value) { - if (strpos($value, "\n") !== false || - substr($value, 0, 2) === ' ') { - $commit_message[] = "{$label}:\n{$value}"; - } else { - $commit_message[] = "{$label}: {$value}"; - } - } - } - - return array( - 'title' => $title, - 'body' => implode("\n\n", $commit_message), - ); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,228 +0,0 @@ -<?php - -final class ReleephWorkNextRequestConduitAPIMethod - extends ReleephConduitAPIMethod { - - private $project; - private $branch; - - public function getAPIMethodName() { - return 'releephwork.nextrequest'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht( - 'Return info required to cut a branch, and pick and revert %s.', - 'ReleephRequests'); - } - - protected function defineParamTypes() { - return array( - 'branchPHID' => 'required phid', - 'seen' => 'required map<string, bool>', - ); - } - - protected function defineReturnType() { - return ''; - } - - protected function defineErrorTypes() { - return array( - 'ERR-NOT-PUSHER' => pht( - 'You are not listed as a pusher for the Releeph project!'), - ); - } - - protected function execute(ConduitAPIRequest $request) { - $viewer = $request->getUser(); - $seen = $request->getValue('seen'); - - $branch = id(new ReleephBranchQuery()) - ->setViewer($viewer) - ->withPHIDs(array($request->getValue('branchPHID'))) - ->executeOne(); - - $project = $branch->getProduct(); - - $needs_pick = array(); - $needs_revert = array(); - - // Load every request ever made for this branch...?!!! - $releeph_requests = id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withBranchIDs(array($branch->getID())) - ->execute(); - - foreach ($releeph_requests as $candidate) { - $phid = $candidate->getPHID(); - if (idx($seen, $phid)) { - continue; - } - - $should = $candidate->shouldBeInBranch(); - $in = $candidate->getInBranch(); - if ($should && !$in) { - $needs_pick[] = $candidate; - } - if (!$should && $in) { - $needs_revert[] = $candidate; - } - } - - /** - * Sort both needs_pick and needs_revert in ascending commit order, as - * discovered by Phabricator (using the `id` column to perform that - * ordering). - * - * This is easy for $needs_pick as the ordinal is stored. It is hard for - * reverts, as we have to look that information up. - */ - $needs_pick = $this->sortPicks($needs_pick); - $needs_revert = $this->sortReverts($needs_revert); - - /** - * Do reverts first in reverse order, then the picks in original-commit - * order. - * - * This seems like the correct thing to do, but there may be a better - * algorithm for the releephwork.nextrequest Conduit call that orders - * things better. - * - * We could also button-mash our way through everything that failed (at the - * end of the run) to try failed things again. - */ - $releeph_request = null; - $action = null; - if ($needs_revert) { - $releeph_request = last($needs_revert); - $action = 'revert'; - $commit_id = $releeph_request->getCommitIdentifier(); - $commit_phid = $releeph_request->getCommitPHID(); - } else if ($needs_pick) { - $releeph_request = head($needs_pick); - $action = 'pick'; - $commit = $releeph_request->loadPhabricatorRepositoryCommit(); - $commit_id = $commit->getCommitIdentifier(); - $commit_phid = $commit->getPHID(); - } else { - // Return early if there's nothing to do! - return array(); - } - - // Build the response - $phids = array(); - $phids[] = $commit_phid; - - $diff_phid = null; - $diff_rev_id = null; - - $requested_object = $releeph_request->getRequestedObject(); - if ($requested_object instanceof DifferentialRevision) { - $diff_rev = $requested_object; - } else { - $diff_rev = null; - } - - if ($diff_rev) { - $diff_phid = $diff_rev->getPHID(); - $phids[] = $diff_phid; - $diff_rev_id = $diff_rev->getID(); - } - - $phids[] = $releeph_request->getPHID(); - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($request->getUser()) - ->withPHIDs($phids) - ->execute(); - - $diff_name = null; - if ($diff_rev) { - $diff_name = $handles[$diff_phid]->getName(); - } - - $new_author_phid = null; - if ($diff_rev) { - $new_author_phid = $diff_rev->getAuthorPHID(); - } else { - $pr_commit = $releeph_request->loadPhabricatorRepositoryCommit(); - if ($pr_commit) { - $new_author_phid = $pr_commit->getAuthorPHID(); - } - } - - return array( - 'requestID' => $releeph_request->getID(), - 'requestPHID' => $releeph_request->getPHID(), - 'requestName' => $handles[$releeph_request->getPHID()]->getName(), - 'requestorPHID' => $releeph_request->getRequestUserPHID(), - 'action' => $action, - 'diffRevID' => $diff_rev_id, - 'diffName' => $diff_name, - 'commitIdentifier' => $commit_id, - 'commitPHID' => $commit_phid, - 'commitName' => $handles[$commit_phid]->getName(), - 'needsRevert' => mpull($needs_revert, 'getID'), - 'needsPick' => mpull($needs_pick, 'getID'), - 'newAuthorPHID' => $new_author_phid, - ); - } - - private function sortPicks(array $releeph_requests) { - $surrogate = array(); - foreach ($releeph_requests as $rq) { - // TODO: it's likely that relying on the `id` column to provide - // trunk-commit-order is thoroughly broken. - $ordinal = (int)$rq->loadPhabricatorRepositoryCommit()->getID(); - $surrogate[$ordinal] = $rq; - } - ksort($surrogate); - return $surrogate; - } - - /** - * Sort an array of ReleephRequests, that have been picked into a branch, in - * the order in which they were picked to the branch. - */ - private function sortReverts(array $releeph_requests) { - if (!$releeph_requests) { - return array(); - } - - // ReleephRequests, keyed by <branch-commit-id> - $releeph_requests = mpull($releeph_requests, null, 'getCommitIdentifier'); - - $commits = id(new PhabricatorRepositoryCommit()) - ->loadAllWhere( - 'commitIdentifier IN (%Ls)', - mpull($releeph_requests, 'getCommitIdentifier')); - - // A map of <branch-commit-id> => <branch-commit-ordinal> - $surrogate = mpull($commits, 'getID', 'getCommitIdentifier'); - - $unparsed = array(); - $result = array(); - - foreach ($releeph_requests as $commit_id => $releeph_request) { - $ordinal = idx($surrogate, $commit_id); - if ($ordinal) { - $result[$ordinal] = $releeph_request; - } else { - $unparsed[] = $releeph_request; - } - } - - // Sort $result in ascending order - ksort($result); - - // Unparsed commits we'll just have to guess, based on time - $unparsed = msort($unparsed, 'getDateModified'); - - return array_merge($result, $unparsed); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -<?php - -final class ReleephWorkRecordConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releephwork.record'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - /** - * Record that a request was committed locally, and is about to be pushed to - * the remote repository. - * - * This lets us mark a ReleephRequest as being in a branch in real time so - * that no one else tries to pick it. - * - * When the daemons discover this commit in the repository with - * DifferentialReleephRequestFieldSpecification, we'll be able to record the - * commit's PHID as well. That process is slow though, and we don't want to - * wait a whole minute before marking something as cleanly picked or - * reverted. - */ - public function getMethodDescription() { - return pht( - 'Record whether we committed a pick or revert '. - 'to the upstream repository.'); - } - - protected function defineParamTypes() { - $action_const = $this->formatStringConstants( - array( - 'pick', - 'revert', - )); - - return array( - 'requestPHID' => 'required string', - 'action' => 'required '.$action_const, - 'commitIdentifier' => 'required string', - ); - } - - protected function defineReturnType() { - return 'void'; - } - - protected function execute(ConduitAPIRequest $request) { - $action = $request->getValue('action'); - $new_commit_id = $request->getValue('commitIdentifier'); - - $releeph_request = id(new ReleephRequest()) - ->loadOneWhere('phid = %s', $request->getValue('requestPHID')); - - $xactions = array(); - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_COMMIT) - ->setMetadataValue('action', $action) - ->setNewValue($new_commit_id); - - $editor = id(new ReleephRequestTransactionalEditor()) - ->setActor($request->getUser()) - ->setContinueOnNoEffect(true) - ->setContentSource($request->newContentSource()); - - $editor->applyTransactions($releeph_request, $xactions); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -<?php - -final class ReleephWorkRecordPickStatusConduitAPIMethod - extends ReleephConduitAPIMethod { - - public function getAPIMethodName() { - return 'releephwork.recordpickstatus'; - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - - public function getMethodDescription() { - return pht('Record whether a pick or revert was successful or not.'); - } - - protected function defineParamTypes() { - $action_const = $this->formatStringConstants( - array( - 'pick', - 'revert', - )); - - return array( - 'requestPHID' => 'required string', - 'action' => 'required '.$action_const, - 'ok' => 'required bool', - 'dryRun' => 'optional bool', - 'details' => 'optional dict<string, wild>', - ); - } - - protected function defineReturnType() { - return ''; - } - - protected function execute(ConduitAPIRequest $request) { - $action = $request->getValue('action'); - $ok = $request->getValue('ok'); - $dry_run = $request->getValue('dryRun'); - $details = $request->getValue('details', array()); - - switch ($request->getValue('action')) { - case 'pick': - $pick_status = $ok - ? ReleephRequest::PICK_OK - : ReleephRequest::PICK_FAILED; - break; - - case 'revert': - $pick_status = $ok - ? ReleephRequest::REVERT_OK - : ReleephRequest::REVERT_FAILED; - break; - - default: - throw new Exception(pht('Unknown action %s!', $action)); - } - - $releeph_request = id(new ReleephRequest()) - ->loadOneWhere('phid = %s', $request->getValue('requestPHID')); - - $editor = id(new ReleephRequestTransactionalEditor()) - ->setActor($request->getUser()) - ->setContinueOnNoEffect(true) - ->setContentSource($request->newContentSource()); - - $xactions = array(); - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_PICK_STATUS) - ->setMetadataValue('dryRun', $dry_run) - ->setMetadataValue('details', $details) - ->setNewValue($pick_status); - - $editor->applyTransactions($releeph_request, $xactions); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -<?php - -final class PhabricatorReleephApplicationConfigOptions - extends PhabricatorApplicationConfigOptions { - - public function getName() { - return pht('Releeph'); - } - - public function getDescription() { - return pht('Options for configuring Releeph, the release branch tool.'); - } - - public function getIcon() { - return 'fa-flag-checkered'; - } - - public function getGroup() { - return 'apps'; - } - - public function getOptions() { - $default_fields = array( - new ReleephSummaryFieldSpecification(), - new ReleephRequestorFieldSpecification(), - new ReleephSeverityFieldSpecification(), - new ReleephIntentFieldSpecification(), - new ReleephReasonFieldSpecification(), - new ReleephAuthorFieldSpecification(), - new ReleephRevisionFieldSpecification(), - new ReleephOriginalCommitFieldSpecification(), - new ReleephBranchCommitFieldSpecification(), - new ReleephDiffSizeFieldSpecification(), - new ReleephDiffChurnFieldSpecification(), - new ReleephDiffMessageFieldSpecification(), - new ReleephCommitMessageFieldSpecification(), - ); - - $default = array(); - foreach ($default_fields as $default_field) { - $default[$default_field->getFieldKey()] = true; - } - - foreach ($default as $key => $enabled) { - $default[$key] = array( - 'disabled' => !$enabled, - ); - } - - $custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType'; - - return array( - $this->newOption('releeph.fields', $custom_field_type, $default) - ->setCustomData('ReleephFieldSpecification'), - $this->newOption( - 'releeph.default-branch-template', - 'string', - 'releases/%P/%p-%Y%m%d-%v') - ->setDescription( - pht( - 'The default branch template for new branches in unconfigured '. - 'Releeph projects. This is also configurable on a per-project '. - 'basis.')), - ); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/constants/ReleephRequestStatus.php phabricator-0~git20220903/phabricator/src/applications/releeph/constants/ReleephRequestStatus.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/constants/ReleephRequestStatus.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/constants/ReleephRequestStatus.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -<?php - -final class ReleephRequestStatus extends Phobject { - - const STATUS_REQUESTED = 1; - const STATUS_NEEDS_PICK = 2; // aka approved - const STATUS_REJECTED = 3; - const STATUS_ABANDONED = 4; - const STATUS_PICKED = 5; - const STATUS_REVERTED = 6; - const STATUS_NEEDS_REVERT = 7; // aka revert requested - - public static function getStatusDescriptionFor($status) { - $descriptions = array( - self::STATUS_REQUESTED => pht('Requested'), - self::STATUS_REJECTED => pht('Rejected'), - self::STATUS_ABANDONED => pht('Abandoned'), - self::STATUS_PICKED => pht('Pulled'), - self::STATUS_REVERTED => pht('Reverted'), - self::STATUS_NEEDS_PICK => pht('Needs Pull'), - self::STATUS_NEEDS_REVERT => pht('Needs Revert'), - ); - return idx($descriptions, $status, '??'); - } - - public static function getStatusClassSuffixFor($status) { - $description = self::getStatusDescriptionFor($status); - $class = str_replace(' ', '-', strtolower($description)); - return $class; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchAccessController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchAccessController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchAccessController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchAccessController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -<?php - -final class ReleephBranchAccessController extends ReleephBranchController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $action = $request->getURIData('action'); - $id = $request->getURIData('branchID'); - - $branch = id(new ReleephBranchQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$branch) { - return new Aphront404Response(); - } - $this->setBranch($branch); - - switch ($action) { - case 'close': - case 're-open': - break; - default: - return new Aphront404Response(); - } - - $branch_uri = $this->getBranchViewURI($branch); - if ($request->isFormPost()) { - - if ($action == 're-open') { - $is_active = 1; - } else { - $is_active = 0; - } - - id(new ReleephBranchEditor()) - ->setActor($request->getUser()) - ->setReleephBranch($branch) - ->changeBranchAccess($is_active); - - return id(new AphrontReloadResponse())->setURI($branch_uri); - } - - if ($action == 'close') { - $title_text = pht('Really Close Branch?'); - $short = pht('Close Branch'); - $body_text = pht( - 'Really close the branch "%s"?', - phutil_tag('strong', array(), $branch->getBasename())); - $button_text = pht('Close Branch'); - } else { - $title_text = pht('Really Reopen Branch?'); - $short = pht('Reopen Branch'); - $body_text = pht( - 'Really reopen the branch "%s"?', - phutil_tag('strong', array(), $branch->getBasename())); - $button_text = pht('Reopen Branch'); - } - - return $this->newDialog() - ->setTitle($title_text) - ->setShortTitle($short) - ->appendChild($body_text) - ->addSubmitButton($button_text) - ->addCancelButton($branch_uri); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -<?php - -abstract class ReleephBranchController extends ReleephController { - - private $branch; - - public function setBranch($branch) { - $this->branch = $branch; - return $this; - } - - public function getBranch() { - return $this->branch; - } - - protected function buildApplicationCrumbs() { - $crumbs = parent::buildApplicationCrumbs(); - - $branch = $this->getBranch(); - if ($branch) { - $product = $branch->getProduct(); - - $crumbs->addTextCrumb( - $product->getName(), - $this->getProductViewURI($product)); - - $crumbs->addTextCrumb( - $branch->getName(), - $this->getBranchViewURI($branch)); - } - - return $crumbs; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchCreateController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchCreateController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchCreateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchCreateController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -<?php - -final class ReleephBranchCreateController extends ReleephProductController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('projectID'); - - $product = id(new ReleephProductQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$product) { - return new Aphront404Response(); - } - $this->setProduct($product); - - - $cut_point = $request->getStr('cutPoint'); - $symbolic_name = $request->getStr('symbolicName'); - - if (!$cut_point) { - $repository = $product->getRepository(); - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $cut_point = $product->getTrunkBranch(); - break; - } - } - - $e_cut = true; - $errors = array(); - - $branch_date_control = id(new AphrontFormDateControl()) - ->setUser($request->getUser()) - ->setName('templateDate') - ->setLabel(pht('Date')) - ->setCaption(pht('The date used for filling out the branch template.')) - ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY); - $branch_date = $branch_date_control->readValueFromRequest($request); - - if ($request->isFormPost()) { - $cut_commit = null; - if (!$cut_point) { - $e_cut = pht('Required'); - $errors[] = pht('You must give a branch cut point'); - } else { - try { - $finder = id(new ReleephCommitFinder()) - ->setUser($request->getUser()) - ->setReleephProject($product); - $cut_commit = $finder->fromPartial($cut_point); - } catch (Exception $e) { - $e_cut = pht('Invalid'); - $errors[] = $e->getMessage(); - } - } - - if (!$errors) { - $branch = id(new ReleephBranchEditor()) - ->setReleephProject($product) - ->setActor($request->getUser()) - ->newBranchFromCommit( - $cut_commit, - $branch_date, - $symbolic_name); - - $branch_uri = $this->getApplicationURI('branch/'.$branch->getID()); - - return id(new AphrontRedirectResponse()) - ->setURI($branch_uri); - } - } - - $product_uri = $this->getProductViewURI($product); - - $form = id(new AphrontFormView()) - ->setUser($request->getUser()) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Symbolic Name')) - ->setName('symbolicName') - ->setValue($symbolic_name) - ->setCaption(pht( - 'Mutable alternate name, for easy reference, (e.g. "LATEST")'))) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Cut point')) - ->setName('cutPoint') - ->setValue($cut_point) - ->setError($e_cut) - ->setCaption(pht( - 'A commit ID for your repo type, or a Diffusion ID like "rE123"'))) - ->appendChild($branch_date_control) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Cut Branch')) - ->addCancelButton($product_uri)); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Branch')) - ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($form); - - $title = pht('New Branch'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($title); - $crumbs->setBorder(true); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter($box); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchEditController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchEditController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchEditController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -<?php - -final class ReleephBranchEditController extends ReleephBranchController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('branchID'); - - $branch = id(new ReleephBranchQuery()) - ->setViewer($viewer) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->withIDs(array($id)) - ->executeOne(); - if (!$branch) { - return new Aphront404Response(); - } - $this->setBranch($branch); - - $symbolic_name = $request->getStr( - 'symbolicName', - $branch->getSymbolicName()); - - if ($request->isFormPost()) { - $existing_with_same_symbolic_name = - id(new ReleephBranch()) - ->loadOneWhere( - 'id != %d AND releephProjectID = %d AND symbolicName = %s', - $branch->getID(), - $branch->getReleephProjectID(), - $symbolic_name); - - $branch->openTransaction(); - $branch->setSymbolicName($symbolic_name); - - if ($existing_with_same_symbolic_name) { - $existing_with_same_symbolic_name - ->setSymbolicName(null) - ->save(); - } - - $branch->save(); - $branch->saveTransaction(); - - return id(new AphrontRedirectResponse()) - ->setURI($this->getBranchViewURI($branch)); - } - - $phids = array(); - - $phids[] = $creator_phid = $branch->getCreatedByUserPHID(); - $phids[] = $cut_commit_phid = $branch->getCutPointCommitPHID(); - - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($request->getUser()) - ->withPHIDs($phids) - ->execute(); - - $form = id(new AphrontFormView()) - ->setUser($request->getUser()) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel(pht('Branch Name')) - ->setValue($branch->getName())) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Cut Point')) - ->setValue($handles[$cut_commit_phid]->renderLink())) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Created By')) - ->setValue($handles[$creator_phid]->renderLink())) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Symbolic Name')) - ->setName('symbolicName') - ->setValue($symbolic_name) - ->setCaption(pht( - 'Mutable alternate name, for easy reference, (e.g. "LATEST")'))) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton($this->getBranchViewURI($branch)) - ->setValue(pht('Save Branch'))); - - $title = pht( - 'Edit Branch: %s', - $branch->getDisplayNameWithDetail()); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Branch')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($form); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Edit')); - $crumbs->setBorder(true); - - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Edit Branch')) - ->setHeaderIcon('fa-pencil'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter($box); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -<?php - -final class ReleephBranchHistoryController extends ReleephBranchController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('branchID'); - - $branch = id(new ReleephBranchQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$branch) { - return new Aphront404Response(); - } - $this->setBranch($branch); - - $timeline = $this->buildTransactionTimeline( - $branch, - new ReleephBranchTransactionQuery()); - $timeline - ->setShouldTerminate(true); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('History')); - $crumbs->setBorder(true); - - $title = pht('Branch History'); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($timeline); - - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchNamePreviewController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchNamePreviewController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchNamePreviewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchNamePreviewController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -<?php - -final class ReleephBranchNamePreviewController - extends ReleephController { - - public function handleRequest(AphrontRequest $request) { - - $is_symbolic = $request->getBool('isSymbolic'); - $template = $request->getStr('template'); - - if (!$is_symbolic && !$template) { - $template = ReleephBranchTemplate::getDefaultTemplate(); - } - - $repository_phid = $request->getInt('repositoryPHID'); - $fake_commit_handle = - ReleephBranchTemplate::getFakeCommitHandleFor( - $repository_phid, - $request->getUser()); - - list($name, $errors) = id(new ReleephBranchTemplate()) - ->setCommitHandle($fake_commit_handle) - ->setReleephProjectName($request->getStr('projectName')) - ->setSymbolic($is_symbolic) - ->interpolate($template); - - $markup = ''; - - if ($name) { - $markup = phutil_tag( - 'div', - array('class' => 'name'), - $name); - } - - if ($errors) { - $markup .= phutil_tag( - 'div', - array('class' => 'error'), - head($errors)); - } - - return id(new AphrontAjaxResponse()) - ->setContent(array('markup' => $markup)); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchViewController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchViewController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/branch/ReleephBranchViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/branch/ReleephBranchViewController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -<?php - -final class ReleephBranchViewController extends ReleephBranchController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('branchID'); - $querykey = $request->getURIData('queryKey'); - - $branch = id(new ReleephBranchQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$branch) { - return new Aphront404Response(); - } - $this->setBranch($branch); - - $controller = id(new PhabricatorApplicationSearchController()) - ->setPreface($this->renderPreface()) - ->setQueryKey($querykey) - ->setSearchEngine($this->getSearchEngine()) - ->setNavigation($this->buildSideNavView()); - - return $this->delegateToController($controller); - } - - - public function buildSideNavView($for_app = false) { - $user = $this->getRequest()->getUser(); - - $nav = new AphrontSideNavFilterView(); - $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); - - $this->getSearchEngine()->addNavigationItems($nav->getMenu()); - - $nav->selectFilter(null); - - return $nav; - } - - private function getSearchEngine() { - $branch = $this->getBranch(); - return id(new ReleephRequestSearchEngine()) - ->setBranch($branch) - ->setBaseURI($this->getApplicationURI('branch/'.$branch->getID().'/')) - ->setViewer($this->getRequest()->getUser()); - } - - protected function buildApplicationCrumbs() { - $crumbs = parent::buildApplicationCrumbs(); - - $branch = $this->getBranch(); - if ($branch) { - $pull_uri = $this->getApplicationURI('branch/pull/'.$branch->getID().'/'); - $crumbs->addAction( - id(new PHUIListItemView()) - ->setHref($pull_uri) - ->setName(pht('New Pull Request')) - ->setIcon('fa-plus-square') - ->setDisabled(!$branch->isActive())); - } - - return $crumbs; - } - - private function renderPreface() { - $viewer = $this->getRequest()->getUser(); - - $branch = $this->getBranch(); - $id = $branch->getID(); - - $header = id(new PHUIHeaderView()) - ->setHeader($branch->getDisplayName()) - ->setUser($viewer) - ->setPolicyObject($branch); - - if ($branch->getIsActive()) { - $header->setStatus('fa-check', 'bluegrey', pht('Active')); - } else { - $header->setStatus('fa-ban', 'dark', pht('Closed')); - } - - $actions = id(new PhabricatorActionListView()) - ->setUser($viewer) - ->setObject($branch); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $branch, - PhabricatorPolicyCapability::CAN_EDIT); - - $edit_uri = $this->getApplicationURI("branch/edit/{$id}/"); - $close_uri = $this->getApplicationURI("branch/close/{$id}/"); - $reopen_uri = $this->getApplicationURI("branch/re-open/{$id}/"); - $history_uri = $this->getApplicationURI("branch/{$id}/history/"); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Edit Branch')) - ->setHref($edit_uri) - ->setIcon('fa-pencil') - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - if ($branch->getIsActive()) { - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Close Branch')) - ->setHref($close_uri) - ->setIcon('fa-times') - ->setDisabled(!$can_edit) - ->setWorkflow(true)); - } else { - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Reopen Branch')) - ->setHref($reopen_uri) - ->setIcon('fa-plus') - ->setUser($viewer) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); - } - - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('View History')) - ->setHref($history_uri) - ->setIcon('fa-list')); - - $properties = id(new PHUIPropertyListView()) - ->setUser($viewer) - ->setObject($branch) - ->setActionList($actions); - - $properties->addProperty( - pht('Branch'), - $branch->getName()); - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->addPropertyList($properties); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductActionController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductActionController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductActionController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductActionController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -<?php - -final class ReleephProductActionController extends ReleephProductController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('projectID'); - $action = $request->getURIData('action'); - - $product = id(new ReleephProductQuery()) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->setViewer($viewer) - ->executeOne(); - if (!$product) { - return new Aphront404Response(); - } - - $this->setProduct($product); - - $product_id = $product->getID(); - $product_uri = $this->getProductViewURI($product); - - switch ($action) { - case 'deactivate': - case 'activate': - break; - default: - throw new Aphront404Response(); - } - - if ($request->isFormPost()) { - $type_active = ReleephProductTransaction::TYPE_ACTIVE; - - $xactions = array(); - if ($action == 'activate') { - $xactions[] = id(new ReleephProductTransaction()) - ->setTransactionType($type_active) - ->setNewValue(1); - } else { - $xactions[] = id(new ReleephProductTransaction()) - ->setTransactionType($type_active) - ->setNewValue(0); - } - - $editor = id(new ReleephProductEditor()) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true) - ->setContinueOnMissingFields(true); - - $editor->applyTransactions($product, $xactions); - - return id(new AphrontRedirectResponse())->setURI($product_uri); - } - - if ($action == 'activate') { - $title = pht('Activate Product?'); - $body = pht( - 'Reactivate the product %s?', - phutil_tag('strong', array(), $product->getName())); - $submit = pht('Reactivate Product'); - $short = pht('Deactivate'); - } else { - $title = pht('Really Deactivate Product?'); - $body = pht( - 'Really deactivate the product %s?', - phutil_tag('strong', array(), $product->getName())); - $submit = pht('Deactivate Product'); - $short = pht('Activate'); - } - - return $this->newDialog() - ->setTitle($title) - ->setShortTitle($short) - ->appendParagraph($body) - ->addSubmitButton($submit) - ->addCancelButton($product_uri); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -<?php - -abstract class ReleephProductController extends ReleephController { - - private $product; - - protected function setProduct(ReleephProject $product) { - $this->product = $product; - return $this; - } - - protected function getProduct() { - return $this->product; - } - - protected function buildApplicationCrumbs() { - $crumbs = parent::buildApplicationCrumbs(); - - $product = $this->getProduct(); - if ($product) { - $crumbs->addTextCrumb( - $product->getName(), - $this->getProductViewURI($product)); - } - - return $crumbs; - } - - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductCreateController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductCreateController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductCreateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductCreateController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -<?php - -final class ReleephProductCreateController extends ReleephProductController { - - public function handleRequest(AphrontRequest $request) { - $name = trim($request->getStr('name')); - $trunk_branch = trim($request->getStr('trunkBranch')); - $repository_phid = $request->getStr('repositoryPHID'); - - $e_name = true; - $e_trunk_branch = true; - $errors = array(); - - if ($request->isFormPost()) { - if (!$name) { - $e_name = pht('Required'); - $errors[] = pht( - 'Your product should have a simple, descriptive name.'); - } - - if (!$trunk_branch) { - $e_trunk_branch = pht('Required'); - $errors[] = pht( - 'You must specify which branch you will be picking from.'); - } - - $pr_repository = id(new PhabricatorRepositoryQuery()) - ->setViewer($request->getUser()) - ->withPHIDs(array($repository_phid)) - ->executeOne(); - - - if (!$errors) { - $releeph_product = id(new ReleephProject()) - ->setName($name) - ->setTrunkBranch($trunk_branch) - ->setRepositoryPHID($pr_repository->getPHID()) - ->setCreatedByUserPHID($request->getUser()->getPHID()) - ->setIsActive(1); - - try { - $releeph_product->save(); - - return id(new AphrontRedirectResponse()) - ->setURI($releeph_product->getURI()); - } catch (AphrontDuplicateKeyQueryException $ex) { - $e_name = pht('Not Unique'); - $errors[] = pht('Another product already uses this name.'); - } - } - } - - $repo_options = $this->getRepositorySelectOptions(); - - $product_name_input = id(new AphrontFormTextControl()) - ->setLabel(pht('Name')) - ->setDisableAutocomplete(true) - ->setName('name') - ->setValue($name) - ->setError($e_name) - ->setCaption(pht('A name like "Thrift" but not "Thrift releases".')); - - $repository_input = id(new AphrontFormSelectControl()) - ->setLabel(pht('Repository')) - ->setName('repositoryPHID') - ->setValue($repository_phid) - ->setOptions($repo_options); - - $branch_name_preview = id(new ReleephBranchPreviewView()) - ->setLabel(pht('Example Branch')) - ->addControl('projectName', $product_name_input) - ->addControl('repositoryPHID', $repository_input) - ->addStatic('template', '') - ->addStatic('isSymbolic', false); - - $form = id(new AphrontFormView()) - ->setUser($request->getUser()) - ->appendChild($product_name_input) - ->appendChild($repository_input) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Trunk')) - ->setName('trunkBranch') - ->setValue($trunk_branch) - ->setError($e_trunk_branch) - ->setCaption(pht( - 'The development branch, from which requests will be picked.'))) - ->appendChild($branch_name_preview) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton('/releeph/project/') - ->setValue(pht('Create Release Product'))); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Product')) - ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setForm($form); - - $title = pht('Create New Product'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('New Product')); - $crumbs->setBorder(true); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter($box); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - } - - private function getRepositorySelectOptions() { - $repos = id(new PhabricatorRepositoryQuery()) - ->setViewer($this->getRequest()->getUser()) - ->execute(); - - $repos = msort($repos, 'getName'); - $repos = mpull($repos, null, 'getID'); - - $choices = array(); - - foreach ($repos as $repo_id => $repo) { - $repo_name = $repo->getName(); - $display = $repo->getDisplayName(); - $choices[$repo->getPHID()] = "{$display} ({$repo_name})"; - } - - asort($choices); - return $choices; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductEditController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductEditController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductEditController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,275 +0,0 @@ -<?php - -final class ReleephProductEditController extends ReleephProductController { - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('projectID'); - - $product = id(new ReleephProductQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$product) { - return new Aphront404Response(); - } - $this->setProduct($product); - - $e_name = true; - $e_trunk_branch = true; - $e_branch_template = false; - $errors = array(); - - $product_name = $request->getStr('name', $product->getName()); - - $trunk_branch = $request->getStr('trunkBranch', $product->getTrunkBranch()); - $branch_template = $request->getStr('branchTemplate'); - if ($branch_template === null) { - $branch_template = $product->getDetail('branchTemplate'); - } - $pick_failure_instructions = $request->getStr('pickFailureInstructions', - $product->getDetail('pick_failure_instructions')); - $test_paths = $request->getStr('testPaths'); - if ($test_paths !== null) { - $test_paths = array_filter(explode("\n", $test_paths)); - } else { - $test_paths = $product->getDetail('testPaths', array()); - } - - $repository_phid = $product->getRepositoryPHID(); - - if ($request->isFormPost()) { - $pusher_phids = $request->getArr('pushers'); - - if (!$product_name) { - $e_name = pht('Required'); - $errors[] = - pht('Your Releeph product should have a simple descriptive name.'); - } - - if (!$trunk_branch) { - $e_trunk_branch = pht('Required'); - $errors[] = - pht('You must specify which branch you will be picking from.'); - } - - $other_releeph_products = id(new ReleephProject()) - ->loadAllWhere('id != %d', $product->getID()); - $other_releeph_product_names = mpull($other_releeph_products, - 'getName', 'getID'); - - if (in_array($product_name, $other_releeph_product_names)) { - $errors[] = pht('Releeph product name %s is already taken', - $product_name); - } - - foreach ($test_paths as $test_path) { - $result = @preg_match($test_path, ''); - $is_a_valid_regexp = $result !== false; - if (!$is_a_valid_regexp) { - $errors[] = pht('Please provide a valid regular expression: '. - '%s is not valid', $test_path); - } - } - - $product - ->setName($product_name) - ->setTrunkBranch($trunk_branch) - ->setDetail('pushers', $pusher_phids) - ->setDetail('pick_failure_instructions', $pick_failure_instructions) - ->setDetail('branchTemplate', $branch_template) - ->setDetail('testPaths', $test_paths); - - $fake_commit_handle = ReleephBranchTemplate::getFakeCommitHandleFor( - $repository_phid, - $viewer); - - if ($branch_template) { - list($branch_name, $template_errors) = id(new ReleephBranchTemplate()) - ->setCommitHandle($fake_commit_handle) - ->setReleephProjectName($product_name) - ->interpolate($branch_template); - - if ($template_errors) { - $e_branch_template = pht('Whoopsies!'); - foreach ($template_errors as $template_error) { - $errors[] = pht('Template error: %s', $template_error); - } - } - } - - if (!$errors) { - $product->save(); - - return id(new AphrontRedirectResponse())->setURI($product->getURI()); - } - } - - $pusher_phids = $request->getArr( - 'pushers', - $product->getDetail('pushers', array())); - - $form = id(new AphrontFormView()) - ->setUser($request->getUser()) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Name')) - ->setName('name') - ->setValue($product_name) - ->setError($e_name) - ->setCaption(pht('A name like "Thrift" but not "Thrift releases".'))) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel(pht('Repository')) - ->setValue( - $product->getRepository()->getName())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel(pht('Repository')) - ->setValue( - $product->getRepository()->getName())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel(pht('Releeph Project PHID')) - ->setValue( - $product->getPHID())) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Trunk')) - ->setValue($trunk_branch) - ->setName('trunkBranch') - ->setError($e_trunk_branch)) - ->appendChild( - id(new AphrontFormTextAreaControl()) - ->setLabel(pht('Pick Instructions')) - ->setValue($pick_failure_instructions) - ->setName('pickFailureInstructions') - ->setCaption( - pht('Instructions for pick failures, which will be used '. - 'in emails generated by failed picks'))) - ->appendChild( - id(new AphrontFormTextAreaControl()) - ->setLabel(pht('Tests paths')) - ->setValue(implode("\n", $test_paths)) - ->setName('testPaths') - ->setCaption( - pht('List of strings that all test files contain in their path '. - 'in this project. One string per line. '. - 'Examples: \'__tests__\', \'/javatests/\'...'))); - - $branch_template_input = id(new AphrontFormTextControl()) - ->setName('branchTemplate') - ->setValue($branch_template) - ->setLabel(pht('Branch Template')) - ->setError($e_branch_template) - ->setCaption( - pht("Leave this blank to use your installation's default.")); - - $branch_template_preview = id(new ReleephBranchPreviewView()) - ->setLabel(pht('Preview')) - ->addControl('template', $branch_template_input) - ->addStatic('repositoryPHID', $repository_phid) - ->addStatic('isSymbolic', false) - ->addStatic('projectName', $product->getName()); - - $form - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setLabel(pht('Pushers')) - ->setName('pushers') - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setValue($pusher_phids)) - ->appendChild($branch_template_input) - ->appendChild($branch_template_preview) - ->appendRemarkupInstructions($this->getBranchHelpText()); - - $form - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton('/releeph/product/') - ->setValue(pht('Save'))); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Product')) - ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($form); - - $title = pht('Edit Product'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Edit Product')); - $crumbs->setBorder(true); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-pencil'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter($box); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - - private function getBranchHelpText() { - return <<<EOTEXT - -==== Interpolations ==== - -| Code | Meaning -| ----- | ------- -| `%P` | The name of your product, with spaces changed to "-". -| `%p` | Like %P, but all lowercase. -| `%Y` | The four digit year associated with the branch date. -| `%m` | The two digit month. -| `%d` | The two digit day. -| `%v` | The handle of the commit where the branch was cut ("rXYZa4b3c2d1"). -| `%V` | The abbreviated commit id where the branch was cut ("a4b3c2d1"). -| `%..` | Any other sequence interpreted by `strftime()`. -| `%%` | A literal percent sign. - - -==== Tips for Branch Templates ==== - -Use a directory to separate your release branches from other branches: - - lang=none - releases/%Y-%M-%d-%v - => releases/2012-30-16-rHERGE32cd512a52b7 - -Include a second hierarchy if you share your repository with other products: - - lang=none - releases/%P/%p-release-%Y%m%d-%V - => releases/Tintin/tintin-release-20121116-32cd512a52b7 - -Keep your branch names simple, avoiding strange punctuation, most of which is -forbidden or escaped anyway: - - lang=none, counterexample - releases//..clown-releases..//`date --iso=seconds`-$(sudo halt) - -Include the date early in your template, in an order which sorts properly: - - lang=none - releases/%Y%m%d-%v - => releases/20121116-rHERGE32cd512a52b7 (good!) - - releases/%V-%m.%d.%Y - => releases/32cd512a52b7-11.16.2012 (awful!) - - -EOTEXT; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductHistoryController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductHistoryController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductHistoryController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductHistoryController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -<?php - -final class ReleephProductHistoryController extends ReleephProductController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('projectID'); - - $product = id(new ReleephProductQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$product) { - return new Aphront404Response(); - } - $this->setProduct($product); - - $timeline = $this->buildTransactionTimeline( - $product, - new ReleephProductTransactionQuery()); - $timeline->setShouldTerminate(true); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('History')); - $crumbs->setBorder(true); - - $title = pht('Product History'); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($timeline); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductListController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductListController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductListController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductListController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -<?php - -final class ReleephProductListController extends ReleephController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $query_key = $request->getURIData('queryKey'); - $controller = id(new PhabricatorApplicationSearchController()) - ->setQueryKey($query_key) - ->setSearchEngine(new ReleephProductSearchEngine()) - ->setNavigation($this->buildSideNavView()); - - return $this->delegateToController($controller); - } - - protected function buildApplicationCrumbs() { - $crumbs = parent::buildApplicationCrumbs(); - - $crumbs->addAction( - id(new PHUIListItemView()) - ->setName(pht('Create Product')) - ->setHref($this->getApplicationURI('product/create/')) - ->setIcon('fa-plus-square')); - - return $crumbs; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductViewController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductViewController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/product/ReleephProductViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/product/ReleephProductViewController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,153 +0,0 @@ -<?php - -final class ReleephProductViewController extends ReleephProductController { - - public function shouldAllowPublic() { - return true; - } - - public function handleRequest(AphrontRequest $request) { - $id = $request->getURIData('projectID'); - $query_key = $request->getURIData('queryKey'); - $viewer = $request->getViewer(); - - $product = id(new ReleephProductQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$product) { - return new Aphront404Response(); - } - $this->setProduct($product); - - $controller = id(new PhabricatorApplicationSearchController()) - ->setQueryKey($query_key) - ->setPreface($this->renderPreface()) - ->setSearchEngine( - id(new ReleephBranchSearchEngine()) - ->setProduct($product)) - ->setNavigation($this->buildSideNavView()); - - return $this->delegateToController($controller); - } - - public function buildSideNavView($for_app = false) { - $viewer = $this->getRequest()->getUser(); - $product = $this->getProduct(); - - $nav = new AphrontSideNavFilterView(); - $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); - - if ($for_app) { - $nav->addFilter('product/create/', pht('Create Product')); - } - - id(new ReleephBranchSearchEngine()) - ->setProduct($product) - ->setViewer($viewer) - ->addNavigationItems($nav->getMenu()); - - $nav->selectFilter(null); - - return $nav; - } - - protected function buildApplicationCrumbs() { - $crumbs = parent::buildApplicationCrumbs(); - - $product = $this->getProduct(); - if ($product) { - $crumbs->addAction( - id(new PHUIListItemView()) - ->setHref($product->getURI('cutbranch/')) - ->setName(pht('Cut New Branch')) - ->setIcon('fa-plus')); - } - - return $crumbs; - } - - private function renderPreface() { - $viewer = $this->getRequest()->getUser(); - $product = $this->getProduct(); - - $id = $product->getID(); - - $header = id(new PHUIHeaderView()) - ->setHeader($product->getName()) - ->setUser($viewer) - ->setPolicyObject($product); - - if ($product->getIsActive()) { - $header->setStatus('fa-check', 'bluegrey', pht('Active')); - } else { - $header->setStatus('fa-ban', 'dark', pht('Inactive')); - } - - $actions = id(new PhabricatorActionListView()) - ->setUser($viewer) - ->setObject($product); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $product, - PhabricatorPolicyCapability::CAN_EDIT); - - $edit_uri = $this->getApplicationURI("product/{$id}/edit/"); - $history_uri = $this->getApplicationURI("product/{$id}/history/"); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Edit Product')) - ->setHref($edit_uri) - ->setIcon('fa-pencil') - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - if ($product->getIsActive()) { - $status_name = pht('Deactivate Product'); - $status_href = "product/{$id}/action/deactivate/"; - $status_icon = 'fa-times'; - } else { - $status_name = pht('Reactivate Product'); - $status_href = "product/{$id}/action/activate/"; - $status_icon = 'fa-plus-circle-o'; - } - - $actions->addAction( - id(new PhabricatorActionView()) - ->setName($status_name) - ->setHref($this->getApplicationURI($status_href)) - ->setIcon($status_icon) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setName(pht('View History')) - ->setHref($history_uri) - ->setIcon('fa-list')); - - $properties = id(new PHUIPropertyListView()) - ->setUser($viewer) - ->setObject($product); - - $properties->addProperty( - pht('Repository'), - $product->getRepository()->getName()); - - $properties->setActionList($actions); - - $pushers = $product->getPushers(); - if ($pushers) { - $properties->addProperty( - pht('Pushers'), - $viewer->renderHandleList($pushers)); - } - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->addPropertyList($properties); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/ReleephController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/ReleephController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/ReleephController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/ReleephController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -<?php - -abstract class ReleephController extends PhabricatorController { - - public function buildSideNavView($for_app = false) { - $user = $this->getRequest()->getUser(); - - $nav = new AphrontSideNavFilterView(); - $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); - - if ($for_app) { - $nav->addFilter('project/create/', pht('Create Product')); - } - - id(new ReleephProductSearchEngine()) - ->setViewer($user) - ->addNavigationItems($nav->getMenu()); - - $nav->selectFilter(null); - - return $nav; - } - - public function buildApplicationMenu() { - return $this->buildSideNavView(true)->getMenu(); - } - - - protected function getProductViewURI(ReleephProject $product) { - return $this->getApplicationURI('project/'.$product->getID().'/'); - } - - protected function getBranchViewURI(ReleephBranch $branch) { - return $this->getApplicationURI('branch/'.$branch->getID().'/'); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestActionController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestActionController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestActionController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestActionController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -<?php - -final class ReleephRequestActionController - extends ReleephRequestController { - - public function handleRequest(AphrontRequest $request) { - $action = $request->getURIData('action'); - $id = $request->getURIData('requestID'); - $viewer = $request->getViewer(); - - $request->validateCSRF(); - - $pull = id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$pull) { - return new Aphront404Response(); - } - - $branch = $pull->getBranch(); - $product = $branch->getProduct(); - $origin_uri = '/'.$pull->getMonogram(); - - $editor = id(new ReleephRequestTransactionalEditor()) - ->setActor($viewer) - ->setContinueOnNoEffect(true) - ->setContentSourceFromRequest($request); - - $xactions = array(); - - switch ($action) { - case 'want': - case 'pass': - static $action_map = array( - 'want' => ReleephRequest::INTENT_WANT, - 'pass' => ReleephRequest::INTENT_PASS, - ); - $intent = $action_map[$action]; - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT) - ->setMetadataValue( - 'isAuthoritative', - $product->isAuthoritative($viewer)) - ->setNewValue($intent); - break; - - case 'mark-manually-picked': - case 'mark-manually-reverted': - if ( - $pull->getRequestUserPHID() === $viewer->getPHID() || - $product->isAuthoritative($viewer)) { - - // We're all good! - } else { - throw new Exception( - pht( - "Bug! Only pushers or the requestor can manually change a ". - "request's in-branch status!")); - } - - if ($action === 'mark-manually-picked') { - $in_branch = 1; - $intent = ReleephRequest::INTENT_WANT; - } else { - $in_branch = 0; - $intent = ReleephRequest::INTENT_PASS; - } - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT) - ->setMetadataValue('isManual', true) - ->setMetadataValue('isAuthoritative', true) - ->setNewValue($intent); - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH) - ->setNewValue($in_branch); - - break; - - default: - throw new Exception( - pht('Unknown or unimplemented action %s.', $action)); - } - - $editor->applyTransactions($pull, $xactions); - - if ($request->getBool('render')) { - $field_list = PhabricatorCustomField::getObjectFields( - $pull, - PhabricatorCustomField::ROLE_VIEW); - - $field_list - ->setViewer($viewer) - ->readFieldsFromStorage($pull); - - // TODO: This should be more modern and general. - $engine = id(new PhabricatorMarkupEngine()) - ->setViewer($viewer); - foreach ($field_list->getFields() as $field) { - if ($field->shouldMarkup()) { - $field->setMarkupEngine($engine); - } - } - $engine->process(); - - $pull_box = id(new ReleephRequestView()) - ->setUser($viewer) - ->setCustomFields($field_list) - ->setPullRequest($pull) - ->setIsListView(true); - - return id(new AphrontAjaxResponse())->setContent( - array( - 'markup' => hsprintf('%s', $pull_box), - )); - } - - return id(new AphrontRedirectResponse())->setURI($origin_uri); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestCommentController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestCommentController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestCommentController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestCommentController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -<?php - -final class ReleephRequestCommentController - extends ReleephRequestController { - - public function handleRequest(AphrontRequest $request) { - $id = $request->getURIData('requestID'); - $viewer = $request->getViewer(); - - if (!$request->isFormPost()) { - return new Aphront400Response(); - } - - $pull = id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$pull) { - return new Aphront404Response(); - } - - $is_preview = $request->isPreviewRequest(); - $draft = PhabricatorDraft::buildFromRequest($request); - - $view_uri = $this->getApplicationURI('/'.$pull->getMonogram()); - - $xactions = array(); - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) - ->attachComment( - id(new ReleephRequestTransactionComment()) - ->setContent($request->getStr('comment'))); - - $editor = id(new ReleephRequestTransactionalEditor()) - ->setActor($viewer) - ->setContinueOnNoEffect($request->isContinueRequest()) - ->setContentSourceFromRequest($request) - ->setIsPreview($is_preview); - - try { - $xactions = $editor->applyTransactions($pull, $xactions); - } catch (PhabricatorApplicationTransactionNoEffectException $ex) { - return id(new PhabricatorApplicationTransactionNoEffectResponse()) - ->setCancelURI($view_uri) - ->setException($ex); - } - - if ($draft) { - $draft->replaceOrDelete(); - } - - if ($request->isAjax() && $is_preview) { - return id(new PhabricatorApplicationTransactionResponse()) - ->setObject($pull) - ->setViewer($viewer) - ->setTransactions($xactions) - ->setIsPreview($is_preview); - } else { - return id(new AphrontRedirectResponse()) - ->setURI($view_uri); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -<?php - -abstract class ReleephRequestController extends ReleephController {} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -<?php - -// TODO: After T2222, this is likely unreachable? - -final class ReleephRequestDifferentialCreateController - extends ReleephController { - - private $revision; - - public function handleRequest(AphrontRequest $request) { - $revision_id = $request->getURIData('diffRevID'); - $viewer = $request->getViewer(); - - $diff_rev = id(new DifferentialRevisionQuery()) - ->setViewer($viewer) - ->withIDs(array($revision_id)) - ->executeOne(); - if (!$diff_rev) { - return new Aphront404Response(); - } - $this->revision = $diff_rev; - - $repository = $this->revision->getRepository(); - - $projects = id(new ReleephProject())->loadAllWhere( - 'repositoryPHID = %s AND isActive = 1', - $repository->getPHID()); - if (!$projects) { - throw new Exception( - pht( - "%s belongs to the '%s' repository, ". - "which is not part of any Releeph project!", - 'D'.$this->revision->getID(), - $repository->getMonogram())); - } - - $branches = id(new ReleephBranch())->loadAllWhere( - 'releephProjectID IN (%Ld) AND isActive = 1', - mpull($projects, 'getID')); - if (!$branches) { - throw new Exception(pht( - '%s could be in the Releeph project(s) %s, '. - 'but this project / none of these projects have open branches.', - 'D'.$this->revision->getID(), - implode(', ', mpull($projects, 'getName')))); - } - - if (count($branches) === 1) { - return id(new AphrontRedirectResponse()) - ->setURI($this->buildReleephRequestURI(head($branches))); - } - - $projects = msort( - mpull($projects, null, 'getID'), - 'getName'); - - $branch_groups = mgroup($branches, 'getReleephProjectID'); - - require_celerity_resource('releeph-request-differential-create-dialog'); - $dialog = id(new AphrontDialogView()) - ->setUser($viewer) - ->setTitle(pht('Choose Releeph Branch')) - ->setClass('releeph-request-differential-create-dialog') - ->addCancelButton('/D'.$request->getStr('D')); - - $dialog->appendChild( - pht( - 'This differential revision changes code that is associated '. - 'with multiple Releeph branches. Please select the branch '. - 'where you would like this code to be picked.')); - - foreach ($branch_groups as $project_id => $branches) { - $project = idx($projects, $project_id); - $dialog->appendChild( - phutil_tag( - 'h1', - array(), - $project->getName())); - $branches = msort($branches, 'getBasename'); - foreach ($branches as $branch) { - $uri = $this->buildReleephRequestURI($branch); - $dialog->appendChild( - phutil_tag( - 'a', - array( - 'href' => $uri, - ), - $branch->getDisplayNameWithDetail())); - } - } - - return id(new AphrontDialogResponse()) - ->setDialog($dialog); - } - - private function buildReleephRequestURI(ReleephBranch $branch) { - $uri = $branch->getURI('request/'); - return id(new PhutilURI($uri)) - ->replaceQueryParam('D', $this->revision->getID()); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestEditController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestEditController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestEditController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,320 +0,0 @@ -<?php - -final class ReleephRequestEditController extends ReleephBranchController { - - public function handleRequest(AphrontRequest $request) { - $action = $request->getURIData('action'); - $request_id = $request->getURIData('requestID'); - $branch_id = $request->getURIData('branchID'); - $viewer = $request->getViewer(); - - if ($request_id) { - $pull = id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withIDs(array($request_id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$pull) { - return new Aphront404Response(); - } - - $branch = $pull->getBranch(); - - $is_edit = true; - } else { - $branch = id(new ReleephBranchQuery()) - ->setViewer($viewer) - ->withIDs(array($branch_id)) - ->executeOne(); - if (!$branch) { - return new Aphront404Response(); - } - - $pull = id(new ReleephRequest()) - ->setRequestUserPHID($viewer->getPHID()) - ->setBranchID($branch->getID()) - ->setInBranch(0) - ->attachBranch($branch); - - $is_edit = false; - } - $this->setBranch($branch); - - $product = $branch->getProduct(); - - $request_identifier = $request->getStr('requestIdentifierRaw'); - $e_request_identifier = true; - - // Load all the ReleephFieldSpecifications - $selector = $branch->getProduct()->getReleephFieldSelector(); - $fields = $selector->getFieldSpecifications(); - foreach ($fields as $field) { - $field - ->setReleephProject($product) - ->setReleephBranch($branch) - ->setReleephRequest($pull); - } - - $field_list = PhabricatorCustomField::getObjectFields( - $pull, - PhabricatorCustomField::ROLE_EDIT); - foreach ($field_list->getFields() as $field) { - $field - ->setReleephProject($product) - ->setReleephBranch($branch) - ->setReleephRequest($pull); - } - $field_list->readFieldsFromStorage($pull); - - - if ($branch_id) { - $cancel_uri = $this->getApplicationURI('branch/'.$branch_id.'/'); - } else { - $cancel_uri = '/'.$pull->getMonogram(); - } - - // Make edits - $errors = array(); - if ($request->isFormPost()) { - $xactions = array(); - - // The commit-identifier being requested... - if (!$is_edit) { - if ($request_identifier === - ReleephRequestTypeaheadControl::PLACEHOLDER) { - - $errors[] = pht('No commit ID was provided.'); - $e_request_identifier = pht('Required'); - } else { - $pr_commit = null; - $finder = id(new ReleephCommitFinder()) - ->setUser($viewer) - ->setReleephProject($product); - try { - $pr_commit = $finder->fromPartial($request_identifier); - } catch (Exception $e) { - $e_request_identifier = pht('Invalid'); - $errors[] = pht( - 'Request %s is probably not a valid commit.', - $request_identifier); - $errors[] = $e->getMessage(); - } - - if (!$errors) { - $object_phid = $finder->getRequestedObjectPHID(); - if (!$object_phid) { - $object_phid = $pr_commit->getPHID(); - } - - $pull->setRequestedObjectPHID($object_phid); - } - } - - if (!$errors) { - $existing = id(new ReleephRequest()) - ->loadOneWhere('requestCommitPHID = %s AND branchID = %d', - $pr_commit->getPHID(), $branch->getID()); - if ($existing) { - return id(new AphrontRedirectResponse()) - ->setURI('/releeph/request/edit/'.$existing->getID(). - '?existing=1'); - } - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_REQUEST) - ->setNewValue($pr_commit->getPHID()); - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT) - // To help hide these implicit intents... - ->setMetadataValue('isRQCreate', true) - ->setMetadataValue('userPHID', $viewer->getPHID()) - ->setMetadataValue( - 'isAuthoritative', - $product->isAuthoritative($viewer)) - ->setNewValue(ReleephRequest::INTENT_WANT); - } - } - - // TODO: This should happen implicitly while building transactions - // instead. - foreach ($field_list->getFields() as $field) { - $field->readValueFromRequest($request); - } - - if (!$errors) { - foreach ($fields as $field) { - if ($field->isEditable()) { - try { - $data = $request->getRequestData(); - $value = idx($data, $field->getRequiredStorageKey()); - $field->validate($value); - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_EDIT_FIELD) - ->setMetadataValue('fieldClass', get_class($field)) - ->setNewValue($value); - } catch (ReleephFieldParseException $ex) { - $errors[] = $ex->getMessage(); - } - } - } - } - - if (!$errors) { - $editor = id(new ReleephRequestTransactionalEditor()) - ->setActor($viewer) - ->setContinueOnNoEffect(true) - ->setContentSourceFromRequest($request); - $editor->applyTransactions($pull, $xactions); - return id(new AphrontRedirectResponse())->setURI($cancel_uri); - } - } - - $handle_phids = array( - $pull->getRequestUserPHID(), - $pull->getRequestCommitPHID(), - ); - $handle_phids = array_filter($handle_phids); - if ($handle_phids) { - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($viewer) - ->withPHIDs($handle_phids) - ->execute(); - } else { - $handles = array(); - } - - $age_string = ''; - if ($is_edit) { - $age_string = phutil_format_relative_time( - time() - $pull->getDateCreated()).' ago'; - } - - // Warn the user if we've been redirected here because we tried to - // re-request something. - $notice_view = null; - if ($request->getInt('existing')) { - $notice_messages = array( - pht('You are editing an existing pick request!'), - pht( - 'Requested %s by %s', - $age_string, - $handles[$pull->getRequestUserPHID()]->renderLink()), - ); - $notice_view = id(new PHUIInfoView()) - ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) - ->setErrors($notice_messages); - } - - $form = id(new AphrontFormView()) - ->setUser($viewer); - - if ($is_edit) { - $form - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Original Commit')) - ->setValue( - $handles[$pull->getRequestCommitPHID()]->renderLink())) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Requestor')) - ->setValue(hsprintf( - '%s %s', - $handles[$pull->getRequestUserPHID()]->renderLink(), - $age_string))); - } else { - $origin = null; - $diff_rev_id = $request->getStr('D'); - if ($diff_rev_id) { - $diff_rev = id(new DifferentialRevisionQuery()) - ->setViewer($viewer) - ->withIDs(array($diff_rev_id)) - ->executeOne(); - $origin = '/D'.$diff_rev->getID(); - $title = sprintf( - 'D%d: %s', - $diff_rev_id, - $diff_rev->getTitle()); - $form - ->addHiddenInput('requestIdentifierRaw', 'D'.$diff_rev_id) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel(pht('Diff')) - ->setValue($title)); - } else { - $origin = $branch->getURI(); - $repo = $product->getRepository(); - $branch_cut_point = id(new PhabricatorRepositoryCommit()) - ->loadOneWhere( - 'phid = %s', - $branch->getCutPointCommitPHID()); - $form->appendChild( - id(new ReleephRequestTypeaheadControl()) - ->setName('requestIdentifierRaw') - ->setLabel(pht('Commit ID')) - ->setRepo($repo) - ->setValue($request_identifier) - ->setError($e_request_identifier) - ->setStartTime($branch_cut_point->getEpoch()) - ->setCaption( - pht( - 'Start typing to autocomplete on commit title, '. - 'or give a Phabricator commit identifier like rFOO1234.'))); - } - } - - $field_list->appendFieldsToForm($form); - - $crumbs = $this->buildApplicationCrumbs(); - - if ($is_edit) { - $title = pht('Edit Pull Request'); - $submit_name = pht('Save'); - $header_icon = 'fa-pencil'; - - $crumbs->addTextCrumb($pull->getMonogram(), '/'.$pull->getMonogram()); - $crumbs->addTextCrumb(pht('Edit')); - } else { - $title = pht('Create Pull Request'); - $submit_name = pht('Create Pull Request'); - $header_icon = 'fa-plus-square'; - - $crumbs->addTextCrumb(pht('New Pull Request')); - } - - $form->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton($cancel_uri, pht('Cancel')) - ->setValue($submit_name)); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Request')) - ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($form); - - $crumbs->setBorder(true); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter(array( - $notice_view, - $box, - )); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestTypeaheadController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestTypeaheadController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestTypeaheadController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestTypeaheadController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -<?php - -final class ReleephRequestTypeaheadController - extends PhabricatorTypeaheadDatasourceController { - - public function handleRequest(AphrontRequest $request) { - $query = $request->getStr('q'); - $repo_id = $request->getInt('repo'); - $since = $request->getInt('since'); - $limit = $request->getInt('limit'); - - $now = time(); - $data = array(); - - // Dummy instances used for getting connections, table names, etc. - $pr_commit = new PhabricatorRepositoryCommit(); - $pr_commit_data = new PhabricatorRepositoryCommitData(); - - $conn = $pr_commit->establishConnection('r'); - - $rows = queryfx_all( - $conn, - 'SELECT - rc.phid as commitPHID, - rc.authorPHID, - rcd.authorName, - SUBSTRING(rcd.commitMessage, 1, 100) AS shortMessage, - rc.commitIdentifier, - rc.epoch - FROM %T rc - INNER JOIN %T rcd ON rcd.commitID = rc.id - WHERE repositoryID = %d - AND rc.epoch >= %d - AND ( - rcd.commitMessage LIKE %~ - OR - rc.commitIdentifier LIKE %~ - ) - ORDER BY rc.epoch DESC - LIMIT %d', - $pr_commit->getTableName(), - $pr_commit_data->getTableName(), - $repo_id, - $since, - $query, - $query, - $limit); - - foreach ($rows as $row) { - $full_commit_id = $row['commitIdentifier']; - $short_commit_id = substr($full_commit_id, 0, 12); - $first_line = $this->getFirstLine($row['shortMessage']); - $data[] = array( - $full_commit_id, - $short_commit_id, - $row['authorName'], - phutil_format_relative_time($now - $row['epoch']), - $first_line, - ); - } - - return id(new AphrontAjaxResponse()) - ->setContent($data); - } - - /** - * Split either at the first new line, or a bunch of dashes. - * - * Really just a legacy from old Releeph Daemon commit messages where I used - * to say: - * - * Commit of FOO for BAR - * ------------ - * This does X Y Z - * - */ - private function getFirstLine($commit_message_fragment) { - static $separators = array('-------', "\n"); - $string = ltrim($commit_message_fragment); - $first_line = $string; - foreach ($separators as $separator) { - if ($pos = strpos($string, $separator)) { - $first_line = substr($string, 0, $pos); - break; - } - } - return $first_line; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestViewController.php phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestViewController.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/controller/request/ReleephRequestViewController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/controller/request/ReleephRequestViewController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -<?php - -final class ReleephRequestViewController - extends ReleephBranchController { - - public function handleRequest(AphrontRequest $request) { - $id = $request->getURIData('requestID'); - $viewer = $request->getViewer(); - - $pull = id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$pull) { - return new Aphront404Response(); - } - $this->setBranch($pull->getBranch()); - - // Redirect older URIs to new "Y" URIs. - // TODO: Get rid of this eventually. - $actual_path = $request->getRequestURI()->getPath(); - $expect_path = '/'.$pull->getMonogram(); - if ($actual_path != $expect_path) { - return id(new AphrontRedirectResponse())->setURI($expect_path); - } - - // TODO: Break this 1:1 stuff? - $branch = $pull->getBranch(); - - $field_list = PhabricatorCustomField::getObjectFields( - $pull, - PhabricatorCustomField::ROLE_VIEW); - - $field_list - ->setViewer($viewer) - ->readFieldsFromStorage($pull); - - // TODO: This should be more modern and general. - $engine = id(new PhabricatorMarkupEngine()) - ->setViewer($viewer); - foreach ($field_list->getFields() as $field) { - if ($field->shouldMarkup()) { - $field->setMarkupEngine($engine); - } - } - $engine->process(); - - $pull_box = id(new ReleephRequestView()) - ->setUser($viewer) - ->setCustomFields($field_list) - ->setPullRequest($pull); - - $timeline = $this->buildTransactionTimeline( - $pull, - new ReleephRequestTransactionQuery()); - - $add_comment_header = pht('Plea or Yield'); - - $draft = PhabricatorDraft::newFromUserAndKey( - $viewer, - $pull->getPHID()); - - $title = hsprintf( - '%s %s', - $pull->getMonogram(), - $pull->getSummaryForDisplay()); - - $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) - ->setUser($viewer) - ->setObjectPHID($pull->getPHID()) - ->setDraft($draft) - ->setHeaderText($add_comment_header) - ->setAction($this->getApplicationURI( - '/request/comment/'.$pull->getID().'/')) - ->setSubmitButtonName(pht('Comment')); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($pull->getMonogram(), '/'.$pull->getMonogram()); - $crumbs->setBorder(true); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-flag-checkered'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter(array( - $pull_box, - $timeline, - $add_comment_form, - )); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,384 +0,0 @@ -<?php - -/** - * This DifferentialFieldSpecification exists for two reason: - * - * 1: To parse "Releeph: picks RQ<nn>" headers in commits created by - * arc-releeph so that RQs committed by arc-releeph have real - * PhabricatorRepositoryCommits associated with them (instead of just the SHA - * of the commit, as seen by the pusher). - * - * 2: If requestors want to commit directly to their release branch, they can - * use this header to (i) indicate on a differential revision that this - * differential revision is for the release branch, and (ii) when they land - * their diff on to the release branch manually, the ReleephRequest is - * automatically updated (instead of having to use the "Mark Manually Picked" - * button.) - * - */ -final class DifferentialReleephRequestFieldSpecification extends Phobject { - - // TODO: This class is essentially dead right now, see T2222. - - const ACTION_PICKS = 'picks'; - const ACTION_REVERTS = 'reverts'; - - private $releephAction; - private $releephPHIDs = array(); - - public function getStorageKey() { - return 'releeph:actions'; - } - - public function getValueForStorage() { - return json_encode(array( - 'releephAction' => $this->releephAction, - 'releephPHIDs' => $this->releephPHIDs, - )); - } - - public function setValueFromStorage($json) { - if ($json) { - $dict = phutil_json_decode($json); - $this->releephAction = idx($dict, 'releephAction'); - $this->releephPHIDs = idx($dict, 'releephPHIDs'); - } - return $this; - } - - public function shouldAppearOnRevisionView() { - return true; - } - - public function renderLabelForRevisionView() { - return pht('Releeph'); - } - - public function getRequiredHandlePHIDs() { - return mpull($this->loadReleephRequests(), 'getPHID'); - } - - public function renderValueForRevisionView() { - static $tense; - - if ($tense === null) { - $tense = array( - self::ACTION_PICKS => array( - 'future' => pht('Will pick'), - 'past' => pht('Picked'), - ), - self::ACTION_REVERTS => array( - 'future' => pht('Will revert'), - 'past' => pht('Reverted'), - ), - ); - } - - $releeph_requests = $this->loadReleephRequests(); - if (!$releeph_requests) { - return null; - } - - if ($this->getRevision()->isClosed()) { - $verb = $tense[$this->releephAction]['past']; - } else { - $verb = $tense[$this->releephAction]['future']; - } - - $parts = hsprintf('%s...', $verb); - foreach ($releeph_requests as $releeph_request) { - $parts->appendHTML(phutil_tag('br')); - $parts->appendHTML( - $this->getHandle($releeph_request->getPHID())->renderLink()); - } - - return $parts; - } - - public function shouldAppearOnCommitMessage() { - return true; - } - - public function getCommitMessageKey() { - return 'releephActions'; - } - - public function setValueFromParsedCommitMessage($dict) { - $this->releephAction = $dict['releephAction']; - $this->releephPHIDs = $dict['releephPHIDs']; - return $this; - } - - public function renderValueForCommitMessage($is_edit) { - $releeph_requests = $this->loadReleephRequests(); - if (!$releeph_requests) { - return null; - } - - $parts = array($this->releephAction); - foreach ($releeph_requests as $releeph_request) { - $parts[] = 'RQ'.$releeph_request->getID(); - } - - return implode(' ', $parts); - } - - /** - * Releeph fields should look like: - * - * Releeph: picks RQ1 RQ2, RQ3 - * Releeph: reverts RQ1 - */ - public function parseValueFromCommitMessage($value) { - /** - * Releeph commit messages look like this (but with more blank lines, - * omitted here): - * - * Make CaptainHaddock more reasonable - * Releeph: picks RQ1 - * Requested By: edward - * Approved By: edward (requestor) - * Request Reason: x - * Summary: Make the Haddock implementation more reasonable. - * Test Plan: none - * Reviewers: user1 - * - * Some of these fields are recognized by Differential (e.g. "Requested - * By"). They are folded up into the "Releeph" field, parsed by this - * class. As such $value includes more than just the first-line: - * - * "picks RQ1\n\nRequested By: edward\n\nApproved By: edward (requestor)" - * - * To hack around this, just consider the first line of $value when - * determining what Releeph actions the parsed commit is performing. - */ - $first_line = head(array_filter(explode("\n", $value))); - - $tokens = preg_split('/\s*,?\s+/', $first_line); - $raw_action = array_shift($tokens); - $action = strtolower($raw_action); - - if (!$action) { - return null; - } - - switch ($action) { - case self::ACTION_REVERTS: - case self::ACTION_PICKS: - break; - - default: - throw new DifferentialFieldParseException( - pht( - "Commit message contains unknown Releeph action '%s'!", - $raw_action)); - break; - } - - $releeph_requests = array(); - foreach ($tokens as $token) { - $match = array(); - if (!preg_match('/^(?:RQ)?(\d+)$/i', $token, $match)) { - $label = $this->renderLabelForCommitMessage(); - throw new DifferentialFieldParseException( - pht( - "Commit message contains unparseable ". - "Releeph request token '%s'!", - $token)); - } - - $id = (int)$match[1]; - $releeph_request = id(new ReleephRequest())->load($id); - - if (!$releeph_request) { - throw new DifferentialFieldParseException( - pht( - 'Commit message references non existent Releeph request: %s!', - $value)); - } - - $releeph_requests[] = $releeph_request; - } - - if (count($releeph_requests) > 1) { - $rqs_seen = array(); - $groups = array(); - foreach ($releeph_requests as $releeph_request) { - $releeph_branch = $releeph_request->getBranch(); - $branch_name = $releeph_branch->getName(); - $rq_id = 'RQ'.$releeph_request->getID(); - - if (idx($rqs_seen, $rq_id)) { - throw new DifferentialFieldParseException( - pht( - 'Commit message refers to %s multiple times!', - $rq_id)); - } - $rqs_seen[$rq_id] = true; - - if (!isset($groups[$branch_name])) { - $groups[$branch_name] = array(); - } - $groups[$branch_name][] = $rq_id; - } - - if (count($groups) > 1) { - $lists = array(); - foreach ($groups as $branch_name => $rq_ids) { - $lists[] = implode(', ', $rq_ids).' in '.$branch_name; - } - throw new DifferentialFieldParseException( - pht( - 'Commit message references multiple Releeph requests, '. - 'but the requests are in different branches: %s', - implode('; ', $lists))); - } - } - - $phids = mpull($releeph_requests, 'getPHID'); - - $data = array( - 'releephAction' => $action, - 'releephPHIDs' => $phids, - ); - return $data; - } - - public function renderLabelForCommitMessage() { - return pht('Releeph'); - } - - public function shouldAppearOnCommitMessageTemplate() { - return false; - } - - public function didParseCommit( - PhabricatorRepository $repo, - PhabricatorRepositoryCommit $commit, - PhabricatorRepositoryCommitData $data) { - - // NOTE: This is currently dead code. See T2222. - - $releeph_requests = $this->loadReleephRequests(); - - if (!$releeph_requests) { - return; - } - - $releeph_branch = head($releeph_requests)->getBranch(); - if (!$this->isCommitOnBranch($repo, $commit, $releeph_branch)) { - return; - } - - foreach ($releeph_requests as $releeph_request) { - if ($this->releephAction === self::ACTION_PICKS) { - $action = 'pick'; - } else { - $action = 'revert'; - } - - $actor_phid = coalesce( - $data->getCommitDetail('committerPHID'), - $data->getCommitDetail('authorPHID')); - - $actor = id(new PhabricatorUser()) - ->loadOneWhere('phid = %s', $actor_phid); - - $xactions = array(); - - $xactions[] = id(new ReleephRequestTransaction()) - ->setTransactionType(ReleephRequestTransaction::TYPE_DISCOVERY) - ->setMetadataValue('action', $action) - ->setMetadataValue('authorPHID', - $data->getCommitDetail('authorPHID')) - ->setMetadataValue('committerPHID', - $data->getCommitDetail('committerPHID')) - ->setNewValue($commit->getPHID()); - - $editor = id(new ReleephRequestTransactionalEditor()) - ->setActor($actor) - ->setContinueOnNoEffect(true) - ->setContentSource( - PhabricatorContentSource::newForSource( - PhabricatorUnknownContentSource::SOURCECONST)); - - $editor->applyTransactions($releeph_request, $xactions); - } - } - - private function loadReleephRequests() { - if (!$this->releephPHIDs) { - return array(); - } - - return id(new ReleephRequestQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($this->releephPHIDs) - ->execute(); - } - - private function isCommitOnBranch( - PhabricatorRepository $repo, - PhabricatorRepositoryCommit $commit, - ReleephBranch $releeph_branch) { - - switch ($repo->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - list($output) = $repo->execxLocalCommand( - 'branch --all --no-color --contains %s', - $commit->getCommitIdentifier()); - - $remote_prefix = 'remotes/origin/'; - $branches = array(); - foreach (array_filter(explode("\n", $output)) as $line) { - $tokens = explode(' ', $line); - $ref = last($tokens); - if (strncmp($ref, $remote_prefix, strlen($remote_prefix)) === 0) { - $branch = substr($ref, strlen($remote_prefix)); - $branches[$branch] = $branch; - } - } - - return idx($branches, $releeph_branch->getName()); - break; - - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest( - DiffusionRequest::newFromDictionary(array( - 'user' => $this->getUser(), - 'repository' => $repo, - 'commit' => $commit->getCommitIdentifier(), - ))); - $path_changes = $change_query->loadChanges(); - $commit_paths = mpull($path_changes, 'getPath'); - - $branch_path = $releeph_branch->getName(); - - $in_branch = array(); - $ex_branch = array(); - foreach ($commit_paths as $path) { - if (strncmp($path, $branch_path, strlen($branch_path)) === 0) { - $in_branch[] = $path; - } else { - $ex_branch[] = $path; - } - } - - if ($in_branch && $ex_branch) { - $error = pht( - 'CONFUSION: commit %s in %s contains %d path change(s) that were '. - 'part of a Releeph branch, but also has %d path change(s) not '. - 'part of a Releeph branch!', - $commit->getCommitIdentifier(), - $repo->getDisplayName(), - count($in_branch), - count($ex_branch)); - phlog($error); - } - - return !empty($in_branch); - break; - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/editor/ReleephBranchEditor.php phabricator-0~git20220903/phabricator/src/applications/releeph/editor/ReleephBranchEditor.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/editor/ReleephBranchEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/editor/ReleephBranchEditor.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -<?php - -final class ReleephBranchEditor extends PhabricatorEditor { - - private $releephProject; - private $releephBranch; - - public function setReleephProject(ReleephProject $rp) { - $this->releephProject = $rp; - return $this; - } - - public function setReleephBranch(ReleephBranch $branch) { - $this->releephBranch = $branch; - return $this; - } - - public function newBranchFromCommit( - PhabricatorRepositoryCommit $cut_point, - $branch_date, - $symbolic_name = null) { - - $template = $this->releephProject->getDetail('branchTemplate'); - if (!$template) { - $template = ReleephBranchTemplate::getRequiredDefaultTemplate(); - } - - $cut_point_handle = id(new PhabricatorHandleQuery()) - ->setViewer($this->requireActor()) - ->withPHIDs(array($cut_point->getPHID())) - ->executeOne(); - - list($name, $errors) = id(new ReleephBranchTemplate()) - ->setCommitHandle($cut_point_handle) - ->setBranchDate($branch_date) - ->setReleephProjectName($this->releephProject->getName()) - ->interpolate($template); - - $basename = last(explode('/', $name)); - - $table = id(new ReleephBranch()); - $transaction = $table->openTransaction(); - $branch = id(new ReleephBranch()) - ->setName($name) - ->setBasename($basename) - ->setReleephProjectID($this->releephProject->getID()) - ->setCreatedByUserPHID($this->requireActor()->getPHID()) - ->setCutPointCommitPHID($cut_point->getPHID()) - ->setIsActive(1) - ->setDetail('branchDate', $branch_date) - ->save(); - - /** - * Steal the symbolic name from any other branch that has it (in this - * project). - */ - if ($symbolic_name) { - $others = id(new ReleephBranch())->loadAllWhere( - 'releephProjectID = %d', - $this->releephProject->getID()); - foreach ($others as $other) { - if ($other->getSymbolicName() == $symbolic_name) { - $other - ->setSymbolicName(null) - ->save(); - } - } - $branch - ->setSymbolicName($symbolic_name) - ->save(); - } - - $table->saveTransaction(); - return $branch; - } - - // aka "close" and "reopen" - public function changeBranchAccess($is_active) { - $branch = $this->releephBranch; - - $branch - ->setIsActive((int)$is_active) - ->save(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/editor/ReleephProductEditor.php phabricator-0~git20220903/phabricator/src/applications/releeph/editor/ReleephProductEditor.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/editor/ReleephProductEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/editor/ReleephProductEditor.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -<?php - -final class ReleephProductEditor - extends PhabricatorApplicationTransactionEditor { - - public function getEditorApplicationClass() { - return 'PhabricatorReleephApplication'; - } - - public function getEditorObjectsDescription() { - return pht('Releeph Products'); - } - - public function getTransactionTypes() { - $types = parent::getTransactionTypes(); - - $types[] = ReleephProductTransaction::TYPE_ACTIVE; - - return $types; - } - - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case ReleephProductTransaction::TYPE_ACTIVE: - return (int)$object->getIsActive(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case ReleephProductTransaction::TYPE_ACTIVE: - return (int)$xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - $new = $xaction->getNewValue(); - - switch ($xaction->getTransactionType()) { - case ReleephProductTransaction::TYPE_ACTIVE: - $object->setIsActive($new); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - return; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php phabricator-0~git20220903/phabricator/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/editor/ReleephRequestTransactionalEditor.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,307 +0,0 @@ -<?php - -final class ReleephRequestTransactionalEditor - extends PhabricatorApplicationTransactionEditor { - - public function getEditorApplicationClass() { - return 'PhabricatorReleephApplication'; - } - - public function getEditorObjectsDescription() { - return pht('Releeph Requests'); - } - - public function getTransactionTypes() { - $types = parent::getTransactionTypes(); - - $types[] = PhabricatorTransactions::TYPE_COMMENT; - $types[] = ReleephRequestTransaction::TYPE_COMMIT; - $types[] = ReleephRequestTransaction::TYPE_DISCOVERY; - $types[] = ReleephRequestTransaction::TYPE_EDIT_FIELD; - $types[] = ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH; - $types[] = ReleephRequestTransaction::TYPE_PICK_STATUS; - $types[] = ReleephRequestTransaction::TYPE_REQUEST; - $types[] = ReleephRequestTransaction::TYPE_USER_INTENT; - - return $types; - } - - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case ReleephRequestTransaction::TYPE_REQUEST: - return $object->getRequestCommitPHID(); - - case ReleephRequestTransaction::TYPE_EDIT_FIELD: - $field = newv($xaction->getMetadataValue('fieldClass'), array()); - $value = $field->setReleephRequest($object)->getValue(); - return $value; - - case ReleephRequestTransaction::TYPE_USER_INTENT: - $user_phid = $xaction->getAuthorPHID(); - return idx($object->getUserIntents(), $user_phid); - - case ReleephRequestTransaction::TYPE_PICK_STATUS: - return (int)$object->getPickStatus(); - break; - - case ReleephRequestTransaction::TYPE_COMMIT: - return $object->getCommitIdentifier(); - - case ReleephRequestTransaction::TYPE_DISCOVERY: - return $object->getCommitPHID(); - - case ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH: - return $object->getInBranch(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case ReleephRequestTransaction::TYPE_REQUEST: - case ReleephRequestTransaction::TYPE_USER_INTENT: - case ReleephRequestTransaction::TYPE_EDIT_FIELD: - case ReleephRequestTransaction::TYPE_PICK_STATUS: - case ReleephRequestTransaction::TYPE_COMMIT: - case ReleephRequestTransaction::TYPE_DISCOVERY: - case ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH: - return $xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $new = $xaction->getNewValue(); - - switch ($xaction->getTransactionType()) { - case ReleephRequestTransaction::TYPE_REQUEST: - $object->setRequestCommitPHID($new); - break; - - case ReleephRequestTransaction::TYPE_USER_INTENT: - $user_phid = $xaction->getAuthorPHID(); - $intents = $object->getUserIntents(); - $intents[$user_phid] = $new; - $object->setUserIntents($intents); - break; - - case ReleephRequestTransaction::TYPE_EDIT_FIELD: - $field = newv($xaction->getMetadataValue('fieldClass'), array()); - $field - ->setReleephRequest($object) - ->setValue($new); - break; - - case ReleephRequestTransaction::TYPE_PICK_STATUS: - $object->setPickStatus($new); - break; - - case ReleephRequestTransaction::TYPE_COMMIT: - $this->setInBranchFromAction($object, $xaction); - $object->setCommitIdentifier($new); - break; - - case ReleephRequestTransaction::TYPE_DISCOVERY: - $this->setInBranchFromAction($object, $xaction); - $object->setCommitPHID($new); - break; - - case ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH: - $object->setInBranch((int)$new); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - return; - } - - protected function filterTransactions( - PhabricatorLiskDAO $object, - array $xactions) { - - // Remove TYPE_DISCOVERY xactions that are the result of a reparse. - $previously_discovered_commits = array(); - $discovery_xactions = idx( - mgroup($xactions, 'getTransactionType'), - ReleephRequestTransaction::TYPE_DISCOVERY); - if ($discovery_xactions) { - $previous_xactions = id(new ReleephRequestTransactionQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withObjectPHIDs(array($object->getPHID())) - ->execute(); - - foreach ($previous_xactions as $xaction) { - if ($xaction->getTransactionType() === - ReleephRequestTransaction::TYPE_DISCOVERY) { - - $commit_phid = $xaction->getNewValue(); - $previously_discovered_commits[$commit_phid] = true; - } - } - } - - foreach ($xactions as $key => $xaction) { - if ($xaction->getTransactionType() === - ReleephRequestTransaction::TYPE_DISCOVERY && - idx($previously_discovered_commits, $xaction->getNewValue())) { - - unset($xactions[$key]); - } - } - - return parent::filterTransactions($object, $xactions); - } - - protected function shouldSendMail( - PhabricatorLiskDAO $object, - array $xactions) { - - // Avoid sending emails that only talk about commit discovery. - $types = array_unique(mpull($xactions, 'getTransactionType')); - if ($types === array(ReleephRequestTransaction::TYPE_DISCOVERY)) { - return false; - } - - // Don't email people when we discover that something picks or reverts OK. - if ($types === array(ReleephRequestTransaction::TYPE_PICK_STATUS)) { - if (!mfilter($xactions, 'isBoringPickStatus', true /* negate */)) { - // If we effectively call "isInterestingPickStatus" and get nothing... - return false; - } - } - - return true; - } - - protected function buildReplyHandler(PhabricatorLiskDAO $object) { - return id(new ReleephRequestReplyHandler()) - ->setActor($this->getActor()) - ->setMailReceiver($object); - } - - protected function getMailSubjectPrefix() { - return '[Releeph]'; - } - - protected function buildMailTemplate(PhabricatorLiskDAO $object) { - $id = $object->getID(); - $title = $object->getSummaryForDisplay(); - return id(new PhabricatorMetaMTAMail()) - ->setSubject("RQ{$id}: {$title}"); - } - - protected function getMailTo(PhabricatorLiskDAO $object) { - $to_phids = array(); - - $product = $object->getBranch()->getProduct(); - foreach ($product->getPushers() as $phid) { - $to_phids[] = $phid; - } - - foreach ($object->getUserIntents() as $phid => $intent) { - $to_phids[] = $phid; - } - - return $to_phids; - } - - protected function getMailCC(PhabricatorLiskDAO $object) { - return array(); - } - - protected function buildMailBody( - PhabricatorLiskDAO $object, - array $xactions) { - - $body = parent::buildMailBody($object, $xactions); - - $rq = $object; - $releeph_branch = $rq->getBranch(); - $releeph_project = $releeph_branch->getProduct(); - - /** - * If any of the events we are emailing about were about a pick failure - * (and/or a revert failure?), include pick failure instructions. - */ - $has_pick_failure = false; - foreach ($xactions as $xaction) { - if ($xaction->getTransactionType() === - ReleephRequestTransaction::TYPE_PICK_STATUS && - $xaction->getNewValue() === ReleephRequest::PICK_FAILED) { - - $has_pick_failure = true; - break; - } - } - if ($has_pick_failure) { - $instructions = $releeph_project->getDetail('pick_failure_instructions'); - if ($instructions) { - $body->addRemarkupSection( - pht('PICK FAILURE INSTRUCTIONS'), - $instructions); - } - } - - $name = sprintf('RQ%s: %s', $rq->getID(), $rq->getSummaryForDisplay()); - $body->addTextSection( - pht('RELEEPH REQUEST'), - $name."\n". - PhabricatorEnv::getProductionURI('/RQ'.$rq->getID())); - - $project_and_branch = sprintf( - '%s - %s', - $releeph_project->getName(), - $releeph_branch->getDisplayNameWithDetail()); - - $body->addTextSection( - pht('RELEEPH BRANCH'), - $project_and_branch."\n". - PhabricatorEnv::getProductionURI($releeph_branch->getURI())); - - return $body; - } - - private function setInBranchFromAction( - ReleephRequest $rq, - ReleephRequestTransaction $xaction) { - - $action = $xaction->getMetadataValue('action'); - switch ($action) { - case 'pick': - $rq->setInBranch(1); - break; - - case 'revert': - $rq->setInBranch(0); - break; - - default: - $id = $rq->getID(); - $type = $xaction->getTransactionType(); - $new = $xaction->getNewValue(); - phlog( - pht( - "Unknown discovery action '%s' for xaction of type %s ". - "with new value %s mentioning %s!", - $action, - $type, - $new, - 'RQ'.$id)); - break; - } - - return $this; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/exception/ReleephFieldParseException.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/exception/ReleephFieldParseException.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/exception/ReleephFieldParseException.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/exception/ReleephFieldParseException.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -<?php - -final class ReleephFieldParseException extends Exception { - - public function __construct(ReleephFieldSpecification $field, - $message) { - - $name = $field->getName(); - parent::__construct("{$name}: {$message}"); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/selector/ReleephDefaultFieldSelector.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/selector/ReleephDefaultFieldSelector.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/selector/ReleephDefaultFieldSelector.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/selector/ReleephDefaultFieldSelector.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -<?php - -final class ReleephDefaultFieldSelector extends ReleephFieldSelector { - - /** - * Determine if this install is Facebook. - * - * TODO: This is a giant hacky mess because I am dumb and moved forward on - * Releeph changes with partial information. Recover from this as gracefully - * as possible. This obviously is an abomination. -epriestley - */ - public static function isFacebook() { - return class_exists('ReleephFacebookKarmaFieldSpecification'); - } - - /** - * @phutil-external-symbol class ReleephFacebookKarmaFieldSpecification - * @phutil-external-symbol class ReleephFacebookSeverityFieldSpecification - * @phutil-external-symbol class ReleephFacebookTagFieldSpecification - * @phutil-external-symbol class ReleephFacebookTasksFieldSpecification - */ - public function getFieldSpecifications() { - if (self::isFacebook()) { - return array( - new ReleephCommitMessageFieldSpecification(), - new ReleephSummaryFieldSpecification(), - new ReleephReasonFieldSpecification(), - new ReleephAuthorFieldSpecification(), - new ReleephRevisionFieldSpecification(), - new ReleephRequestorFieldSpecification(), - new ReleephFacebookKarmaFieldSpecification(), - new ReleephFacebookSeverityFieldSpecification(), - new ReleephOriginalCommitFieldSpecification(), - new ReleephDiffMessageFieldSpecification(), - new ReleephIntentFieldSpecification(), - new ReleephBranchCommitFieldSpecification(), - new ReleephDiffSizeFieldSpecification(), - new ReleephDiffChurnFieldSpecification(), - new ReleephDependsOnFieldSpecification(), - new ReleephFacebookTagFieldSpecification(), - new ReleephFacebookTasksFieldSpecification(), - ); - } else { - return array( - new ReleephCommitMessageFieldSpecification(), - new ReleephSummaryFieldSpecification(), - new ReleephReasonFieldSpecification(), - new ReleephAuthorFieldSpecification(), - new ReleephRevisionFieldSpecification(), - new ReleephRequestorFieldSpecification(), - new ReleephSeverityFieldSpecification(), - new ReleephOriginalCommitFieldSpecification(), - new ReleephDiffMessageFieldSpecification(), - new ReleephIntentFieldSpecification(), - new ReleephBranchCommitFieldSpecification(), - new ReleephDiffSizeFieldSpecification(), - new ReleephDiffChurnFieldSpecification(), - ); - } - } - - public function sortFieldsForCommitMessage(array $fields) { - return self::selectFields($fields, array( - 'ReleephCommitMessageFieldSpecification', - 'ReleephRequestorFieldSpecification', - 'ReleephIntentFieldSpecification', - 'ReleephReasonFieldSpecification', - )); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/selector/ReleephFieldSelector.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/selector/ReleephFieldSelector.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/selector/ReleephFieldSelector.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/selector/ReleephFieldSelector.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -<?php - -abstract class ReleephFieldSelector extends Phobject { - - final public function __construct() { - // <empty> - } - - abstract public function getFieldSpecifications(); - - public function sortFieldsForCommitMessage(array $fields) { - assert_instances_of($fields, 'ReleephFieldSpecification'); - return $fields; - } - - protected static function selectFields(array $fields, array $classes) { - assert_instances_of($fields, 'ReleephFieldSpecification'); - - $map = array(); - foreach ($fields as $field) { - $map[get_class($field)] = $field; - } - - $result = array(); - foreach ($classes as $class) { - $field = idx($map, $class); - if (!$field) { - throw new Exception( - pht( - "Tried to select a in instance of '%s' but that field ". - "is not configured for this project!", - $class)); - } - - if (idx($result, $class)) { - throw new Exception( - pht( - "You have asked to select the field '%s' more than once!", - $class)); - } - - $result[$class] = $field; - } - - return $result; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephAuthorFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephAuthorFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephAuthorFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephAuthorFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -<?php - -final class ReleephAuthorFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'author'; - } - - public function getName() { - return pht('Author'); - } - - public function getRequiredHandlePHIDsForPropertyView() { - $pull = $this->getReleephRequest(); - $commit = $pull->loadPhabricatorRepositoryCommit(); - if (!$commit) { - return array(); - } - - $author_phid = $commit->getAuthorPHID(); - if (!$author_phid) { - return array(); - } - - return array($author_phid); - } - - public function renderPropertyViewValue(array $handles) { - return $this->renderHandleList($handles); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -<?php - -final class ReleephBranchCommitFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'commit'; - } - - public function getName() { - return pht('Commit'); - } - - public function getRequiredHandlePHIDsForPropertyView() { - $pull = $this->getReleephRequest(); - - if ($pull->getCommitPHID()) { - return array($pull->getCommitPHID()); - } - - return array(); - } - - public function renderPropertyViewValue(array $handles) { - return $this->renderHandleList($handles); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -<?php - -final class ReleephCommitMessageFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'commit:apply'; - } - - public function getName() { - return '__only_for_commit_message!'; - } - - public function shouldAppearInPropertyView() { - return false; - } - - public function shouldAppearOnCommitMessage() { - return true; - } - - public function renderLabelForCommitMessage() { - return $this->renderCommonLabel(); - } - - public function renderValueForCommitMessage() { - return $this->renderCommonValue( - DifferentialReleephRequestFieldSpecification::ACTION_PICKS); - } - - public function shouldAppearOnRevertMessage() { - return true; - } - - public function renderLabelForRevertMessage() { - return $this->renderCommonLabel(); - } - - public function renderValueForRevertMessage() { - return $this->renderCommonValue( - DifferentialReleephRequestFieldSpecification::ACTION_REVERTS); - } - - private function renderCommonLabel() { - return id(new DifferentialReleephRequestFieldSpecification()) - ->renderLabelForCommitMessage(); - } - - private function renderCommonValue($action) { - $rq = 'RQ'.$this->getReleephRequest()->getID(); - return "{$action} {$rq}"; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -<?php - -final class ReleephDependsOnFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'dependsOn'; - } - - public function getName() { - return pht('Depends On'); - } - - public function getRequiredHandlePHIDsForPropertyView() { - return $this->getDependentRevisionPHIDs(); - } - - public function renderPropertyViewValue(array $handles) { - return $this->renderHandleList($handles); - } - - private function getDependentRevisionPHIDs() { - $requested_object = $this->getObject()->getRequestedObjectPHID(); - if (!($requested_object instanceof DifferentialRevision)) { - return array(); - } - - $revision = $requested_object; - - return PhabricatorEdgeQuery::loadDestinationPHIDs( - $revision->getPHID(), - DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -<?php - -final class ReleephDiffChurnFieldSpecification - extends ReleephFieldSpecification { - - const REJECTIONS_WEIGHT = 30; - const COMMENTS_WEIGHT = 7; - const UPDATES_WEIGHT = 10; - const MAX_POINTS = 100; - - public function getFieldKey() { - return 'churn'; - } - - public function getName() { - return pht('Churn'); - } - - public function renderPropertyViewValue(array $handles) { - $requested_object = $this->getObject()->getRequestedObject(); - if (!($requested_object instanceof DifferentialRevision)) { - return null; - } - $diff_rev = $requested_object; - - $xactions = id(new DifferentialTransactionQuery()) - ->setViewer($this->getViewer()) - ->withObjectPHIDs(array($diff_rev->getPHID())) - ->execute(); - - $rejections = 0; - $comments = 0; - $updates = 0; - - foreach ($xactions as $xaction) { - switch ($xaction->getTransactionType()) { - case PhabricatorTransactions::TYPE_COMMENT: - $comments++; - break; - case DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE: - $updates++; - break; - case DifferentialTransaction::TYPE_ACTION: - switch ($xaction->getNewValue()) { - case DifferentialAction::ACTION_REJECT: - $rejections++; - break; - } - break; - } - } - - $points = - self::REJECTIONS_WEIGHT * $rejections + - self::COMMENTS_WEIGHT * $comments + - self::UPDATES_WEIGHT * $updates; - - if ($points === 0) { - $points = 0.15 * self::MAX_POINTS; - $blurb = pht('Silent diff'); - } else { - $parts = array(); - if ($rejections) { - $parts[] = pht('%s rejection(s)', new PhutilNumber($rejections)); - } - if ($comments) { - $parts[] = pht('%s comment(s)', new PhutilNumber($comments)); - } - if ($updates) { - $parts[] = pht('%s update(s)', new PhutilNumber($updates)); - } - - if (count($parts) === 0) { - $blurb = ''; - } else if (count($parts) === 1) { - $blurb = head($parts); - } else { - $last = array_pop($parts); - $blurb = pht('%s and %s', implode(', ', $parts), $last); - } - } - - return id(new AphrontProgressBarView()) - ->setValue($points) - ->setMax(self::MAX_POINTS) - ->setCaption($blurb) - ->render(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -<?php - -final class ReleephDiffMessageFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'commit:message'; - } - - public function getName() { - return pht('Message'); - } - - public function getStyleForPropertyView() { - return 'block'; - } - - public function renderPropertyViewValue(array $handles) { - return phutil_tag( - 'div', - array( - 'class' => 'phabricator-remarkup', - ), - $this->getMarkupEngineOutput()); - } - - public function shouldMarkup() { - return true; - } - - public function getMarkupText($field) { - $commit_data = $this - ->getReleephRequest() - ->loadPhabricatorRepositoryCommitData(); - if ($commit_data) { - return $commit_data->getCommitMessage(); - } else { - return ''; - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -<?php - -final class ReleephDiffSizeFieldSpecification - extends ReleephFieldSpecification { - - const LINES_WEIGHT = 1; - const PATHS_WEIGHT = 30; - const MAX_POINTS = 1000; - - public function getFieldKey() { - return 'commit:size'; - } - - public function getName() { - return pht('Size'); - } - - public function renderPropertyViewValue(array $handles) { - $requested_object = $this->getObject()->getRequestedObject(); - if (!($requested_object instanceof DifferentialRevision)) { - return null; - } - $diff_rev = $requested_object; - - $diffs = id(new DifferentialDiff())->loadAllWhere( - 'revisionID = %d AND creationMethod != %s', - $diff_rev->getID(), - 'commit'); - - $all_changesets = array(); - $most_recent_changesets = null; - foreach ($diffs as $diff) { - $changesets = id(new DifferentialChangeset())->loadAllWhere( - 'diffID = %d', - $diff->getID()); - $all_changesets += $changesets; - $most_recent_changesets = $changesets; - } - - // The score is based on all changesets for all versions of this diff - $all_changes = $this->countLinesAndPaths($all_changesets); - $points = - self::LINES_WEIGHT * $all_changes['code']['lines'] + - self::PATHS_WEIGHT * count($all_changes['code']['paths']); - - // The blurb is just based on the most recent version of the diff - $mr_changes = $this->countLinesAndPaths($most_recent_changesets); - - $test_tag = ''; - if ($mr_changes['tests']['paths']) { - Javelin::initBehavior('phabricator-tooltips'); - require_celerity_resource('aphront-tooltip-css'); - - $test_blurb = pht( - "%d line(s) and %d path(s) contain changes to test code:\n", - $mr_changes['tests']['lines'], - count($mr_changes['tests']['paths'])); - foreach ($mr_changes['tests']['paths'] as $mr_test_path) { - $test_blurb .= sprintf("%s\n", $mr_test_path); - } - - $test_tag = javelin_tag( - 'span', - array( - 'sigil' => 'has-tooltip', - 'meta' => array( - 'tip' => $test_blurb, - 'align' => 'E', - 'size' => 'auto', - ), - 'style' => '', - ), - ' + tests'); - } - - $blurb = hsprintf('%s%s.', - pht( - '%d line(s) and %d path(s) over %d diff(s)', - $mr_changes['code']['lines'], - $mr_changes['code']['paths'], - count($diffs)), - $test_tag); - - return id(new AphrontProgressBarView()) - ->setValue($points) - ->setMax(self::MAX_POINTS) - ->setCaption($blurb) - ->render(); - } - - private function countLinesAndPaths(array $changesets) { - assert_instances_of($changesets, 'DifferentialChangeset'); - $lines = 0; - $paths_touched = array(); - $test_lines = 0; - $test_paths_touched = array(); - - foreach ($changesets as $ch) { - if ($this->getReleephProject()->isTestFile($ch->getFilename())) { - $test_lines += $ch->getAddLines() + $ch->getDelLines(); - $test_paths_touched[] = $ch->getFilename(); - } else { - $lines += $ch->getAddLines() + $ch->getDelLines(); - $paths_touched[] = $ch->getFilename(); - } - } - return array( - 'code' => array( - 'lines' => $lines, - 'paths' => array_unique($paths_touched), - ), - 'tests' => array( - 'lines' => $test_lines, - 'paths' => array_unique($test_paths_touched), - ), - ); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,265 +0,0 @@ -<?php - -abstract class ReleephFieldSpecification - extends PhabricatorCustomField - implements PhabricatorMarkupInterface { - - // TODO: This is temporary, until ReleephFieldSpecification is more conformant - // to PhabricatorCustomField. - private $requestValue; - - public function readValueFromRequest(AphrontRequest $request) { - $this->requestValue = $request->getStr($this->getRequiredStorageKey()); - return $this; - } - - public function shouldAppearInPropertyView() { - return true; - } - - public function renderPropertyViewLabel() { - return $this->getName(); - } - - public function renderPropertyViewValue(array $handles) { - $key = $this->getRequiredStorageKey(); - $value = $this->getReleephRequest()->getDetail($key); - if ($value === '') { - return null; - } - return $value; - } - - abstract public function getName(); - -/* -( Storage )------------------------------------------------------------ */ - - public function getStorageKey() { - return null; - } - - public function getRequiredStorageKey() { - $key = $this->getStorageKey(); - if ($key === null) { - throw new PhabricatorCustomFieldImplementationIncompleteException($this); - } - if (strpos($key, '.') !== false) { - /** - * Storage keys are reused for form controls, and periods in form control - * names break HTML forms. - */ - throw new Exception(pht("You can't use '%s' in storage keys!", '.')); - } - return $key; - } - - public function shouldAppearInEditView() { - return $this->isEditable(); - } - - final public function isEditable() { - return $this->getStorageKey() !== null; - } - - final public function getValue() { - if ($this->requestValue !== null) { - return $this->requestValue; - } - - $key = $this->getRequiredStorageKey(); - return $this->getReleephRequest()->getDetail($key); - } - - final public function setValue($value) { - $key = $this->getRequiredStorageKey(); - return $this->getReleephRequest()->setDetail($key, $value); - } - - /** - * @throws ReleephFieldParseException, to show an error. - */ - public function validate($value) { - return; - } - - /** - * Turn values as they are stored in a ReleephRequest into a text that can be - * rendered as a transactions old/new values. - */ - public function normalizeForTransactionView( - PhabricatorApplicationTransaction $xaction, - $value) { - - return $value; - } - - -/* -( Conduit )------------------------------------------------------------ */ - - public function getKeyForConduit() { - return $this->getRequiredStorageKey(); - } - - public function getValueForConduit() { - return $this->getValue(); - } - - public function setValueFromConduitAPIRequest(ConduitAPIRequest $request) { - $value = idx( - $request->getValue('fields', array()), - $this->getRequiredStorageKey()); - $this->validate($value); - $this->setValue($value); - return $this; - } - - -/* -( Arcanist )----------------------------------------------------------- */ - - public function renderHelpForArcanist() { - return ''; - } - - -/* -( Context )------------------------------------------------------------ */ - - private $releephProject; - private $releephBranch; - private $releephRequest; - private $user; - - final public function setReleephProject(ReleephProject $rp) { - $this->releephProject = $rp; - return $this; - } - - final public function setReleephBranch(ReleephBranch $rb) { - $this->releephRequest = $rb; - return $this; - } - - final public function setReleephRequest(ReleephRequest $rr) { - $this->releephRequest = $rr; - return $this; - } - - final public function setUser(PhabricatorUser $user) { - $this->user = $user; - return $this; - } - - final public function getReleephProject() { - if (!$this->releephProject) { - return $this->getReleephBranch()->getProduct(); - } - return $this->releephProject; - } - - final public function getReleephBranch() { - if (!$this->releephBranch) { - return $this->getReleephRequest()->getBranch(); - } - return $this->releephBranch; - } - - final public function getReleephRequest() { - if (!$this->releephRequest) { - return $this->getObject(); - } - return $this->releephRequest; - } - - final public function getUser() { - if (!$this->user) { - return $this->getViewer(); - } - return $this->user; - } - -/* -( Commit Messages )---------------------------------------------------- */ - - public function shouldAppearOnCommitMessage() { - return false; - } - - public function renderLabelForCommitMessage() { - throw new PhabricatorCustomFieldImplementationIncompleteException($this); - } - - public function renderValueForCommitMessage() { - throw new PhabricatorCustomFieldImplementationIncompleteException($this); - } - - public function shouldAppearOnRevertMessage() { - return false; - } - - public function renderLabelForRevertMessage() { - return $this->renderLabelForCommitMessage(); - } - - public function renderValueForRevertMessage() { - return $this->renderValueForCommitMessage(); - } - - -/* -( Markup Interface )--------------------------------------------------- */ - - const MARKUP_FIELD_GENERIC = 'releeph:generic-markup-field'; - - private $engine; - - /** - * @{class:ReleephFieldSpecification} implements much of - * @{interface:PhabricatorMarkupInterface} for you. If you return true from - * `shouldMarkup()`, and implement `getMarkupText()` then your text will be - * rendered through the Phabricator markup pipeline. - * - * Output is retrievable with `getMarkupEngineOutput()`. - */ - public function shouldMarkup() { - return false; - } - - public function getMarkupText($field) { - throw new PhabricatorCustomFieldImplementationIncompleteException($this); - } - - final public function getMarkupEngineOutput() { - return $this->engine->getOutput($this, self::MARKUP_FIELD_GENERIC); - } - - final public function setMarkupEngine(PhabricatorMarkupEngine $engine) { - $this->engine = $engine; - $engine->addObject($this, self::MARKUP_FIELD_GENERIC); - return $this; - } - - final public function getMarkupFieldKey($field) { - $content = sprintf( - '%s:%s:%s:%s', - $this->getReleephRequest()->getPHID(), - $this->getStorageKey(), - $field, - $this->getMarkupText($field)); - - return PhabricatorMarkupEngine::digestRemarkupContent($this, $content); - } - - final public function newMarkupEngine($field) { - return PhabricatorMarkupEngine::newDifferentialMarkupEngine(); - } - - final public function didMarkupText( - $field, - $output, - PhutilMarkupEngine $engine) { - - return $output; - } - - final public function shouldUseMarkupCache($field) { - return true; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephIntentFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephIntentFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephIntentFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephIntentFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -<?php - -final class ReleephIntentFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'intent'; - } - - public function getName() { - return pht('Intent'); - } - - public function getRequiredHandlePHIDsForPropertyView() { - $pull = $this->getReleephRequest(); - $intents = $pull->getUserIntents(); - return array_keys($intents); - } - - public function renderPropertyViewValue(array $handles) { - $pull = $this->getReleephRequest(); - - $intents = $pull->getUserIntents(); - $product = $this->getReleephProject(); - - if (!$intents) { - return null; - } - - $pushers = array(); - $others = array(); - - foreach ($intents as $phid => $intent) { - if ($product->isAuthoritativePHID($phid)) { - $pushers[$phid] = $intent; - } else { - $others[$phid] = $intent; - } - } - - $intents = $pushers + $others; - - $view = id(new PHUIStatusListView()); - foreach ($intents as $phid => $intent) { - switch ($intent) { - case ReleephRequest::INTENT_WANT: - $icon = PHUIStatusItemView::ICON_ACCEPT; - $color = 'green'; - $label = pht('Want'); - break; - case ReleephRequest::INTENT_PASS: - $icon = PHUIStatusItemView::ICON_REJECT; - $color = 'red'; - $label = pht('Pass'); - break; - default: - $icon = PHUIStatusItemView::ICON_QUESTION; - $color = 'bluegrey'; - $label = pht('Unknown Intent (%s)', $intent); - break; - } - - $target = $handles[$phid]->renderLink(); - if ($product->isAuthoritativePHID($phid)) { - $target = phutil_tag('strong', array(), $target); - } - - $view->addItem( - id(new PHUIStatusItemView()) - ->setIcon($icon, $color, $label) - ->setTarget($target)); - } - - return $view; - } - - public function shouldAppearOnCommitMessage() { - return true; - } - - public function shouldAppearOnRevertMessage() { - return true; - } - - public function renderLabelForCommitMessage() { - return pht('Approved By'); - } - - public function renderLabelForRevertMessage() { - return pht('Rejected By'); - } - - public function renderValueForCommitMessage() { - return $this->renderIntentsForCommitMessage(ReleephRequest::INTENT_WANT); - } - - public function renderValueForRevertMessage() { - return $this->renderIntentsForCommitMessage(ReleephRequest::INTENT_PASS); - } - - private function renderIntentsForCommitMessage($print_intent) { - $intents = $this->getReleephRequest()->getUserIntents(); - - $requestor = $this->getReleephRequest()->getRequestUserPHID(); - $pusher_phids = $this->getReleephProject()->getPushers(); - - $phids = array_unique($pusher_phids + array_keys($intents)); - $handles = id(new PhabricatorHandleQuery()) - ->setViewer($this->getUser()) - ->withPHIDs($phids) - ->execute(); - - $tokens = array(); - foreach ($phids as $phid) { - $intent = idx($intents, $phid); - if ($intent == $print_intent) { - $name = $handles[$phid]->getName(); - $is_pusher = in_array($phid, $pusher_phids); - $is_requestor = $phid == $requestor; - - if ($is_pusher) { - if ($is_requestor) { - $token = pht('%s (pusher and requestor)', $name); - } else { - $token = "{$name} (pusher)"; - } - } else { - if ($is_requestor) { - $token = pht('%s (requestor)', $name); - } else { - $token = $name; - } - } - - $tokens[] = $token; - } - } - - return implode(', ', $tokens); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephLevelFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephLevelFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephLevelFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephLevelFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,137 +0,0 @@ -<?php - -/** - * Provides a convenient field for storing a set of levels that you can use to - * filter requests on. - * - * Levels are rendered with names and descriptions in the edit UI, and are - * automatically documented via the "arc request" interface. - * - * See ReleephSeverityFieldSpecification for an example. - */ -abstract class ReleephLevelFieldSpecification - extends ReleephFieldSpecification { - - private $error; - - abstract public function getLevels(); - abstract public function getDefaultLevel(); - abstract public function getNameForLevel($level); - abstract public function getDescriptionForLevel($level); - - public function getStorageKey() { - throw new PhabricatorCustomFieldImplementationIncompleteException($this); - } - - public function renderPropertyViewValue(array $handles) { - return $this->getNameForLevel($this->getValue()); - } - - public function renderEditControl(array $handles) { - $control_name = $this->getRequiredStorageKey(); - $all_levels = $this->getLevels(); - - $level = $this->getValue(); - if (!$level) { - $level = $this->getDefaultLevel(); - } - - $control = id(new AphrontFormRadioButtonControl()) - ->setLabel(pht('Level')) - ->setName($control_name) - ->setValue($level); - - if ($this->error) { - $control->setError($this->error); - } else if ($this->getDefaultLevel()) { - $control->setError(true); - } - - foreach ($all_levels as $level) { - $name = $this->getNameForLevel($level); - $description = $this->getDescriptionForLevel($level); - $control->addButton($level, $name, $description); - } - - return $control; - } - - public function renderHelpForArcanist() { - $text = ''; - $levels = $this->getLevels(); - $default = $this->getDefaultLevel(); - foreach ($levels as $level) { - $name = $this->getNameForLevel($level); - $description = $this->getDescriptionForLevel($level); - $default_marker = ' '; - if ($level === $default) { - $default_marker = '*'; - } - $text .= " {$default_marker} **{$name}**\n"; - $text .= phutil_console_wrap($description."\n", 8); - } - return $text; - } - - public function validate($value) { - if ($value === null) { - $this->error = pht('Required'); - $label = $this->getName(); - throw new ReleephFieldParseException( - $this, - pht('You must provide a %s level.', $label)); - } - - $levels = $this->getLevels(); - if (!in_array($value, $levels)) { - $label = $this->getName(); - throw new ReleephFieldParseException( - $this, - pht( - "Level '%s' is not a valid %s level in this project.", - $value, - $label)); - } - } - - public function setValueFromConduitAPIRequest(ConduitAPIRequest $request) { - $key = $this->getRequiredStorageKey(); - $label = $this->getName(); - $name = idx($request->getValue('fields', array()), $key); - - if (!$name) { - $level = $this->getDefaultLevel(); - if (!$level) { - throw new ReleephFieldParseException( - $this, - pht( - 'No value given for %s, and no default is given for this level!', - $label)); - } - } else { - $level = $this->getLevelByName($name); - } - - if (!$level) { - throw new ReleephFieldParseException( - $this, - pht("Unknown %s level name '%s'", $label, $name)); - } - $this->setValue($level); - return $this; - } - - private $nameMap = array(); - - public function getLevelByName($name) { - // Build this once - if (!$this->nameMap) { - foreach ($this->getLevels() as $level) { - $level_name = $this->getNameForLevel($level); - $this->nameMap[$level_name] = $level; - } - } - return idx($this->nameMap, $name); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -<?php - -final class ReleephOriginalCommitFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'commit:name'; - } - - public function getName() { - return pht('Commit'); - } - - public function getRequiredHandlePHIDsForPropertyView() { - return array( - $this->getReleephRequest()->getRequestCommitPHID(), - ); - } - - - public function renderPropertyViewValue(array $handles) { - return $this->renderHandleList($handles); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephReasonFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephReasonFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephReasonFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephReasonFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -<?php - -final class ReleephReasonFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'reason'; - } - - public function getName() { - return pht('Reason'); - } - - public function getStorageKey() { - return 'reason'; - } - - public function getStyleForPropertyView() { - return 'block'; - } - - public function getIconForPropertyView() { - return PHUIPropertyListView::ICON_SUMMARY; - } - - public function renderPropertyViewValue(array $handles) { - return phutil_tag( - 'div', - array( - 'class' => 'phabricator-remarkup', - ), - $this->getMarkupEngineOutput()); - } - - private $error = true; - - public function renderEditControl(array $handles) { - return id(new AphrontFormTextAreaControl()) - ->setLabel(pht('Reason')) - ->setName('reason') - ->setError($this->error) - ->setValue($this->getValue()); - } - - public function validate($reason) { - if (!$reason) { - $this->error = pht('Required'); - throw new ReleephFieldParseException( - $this, - pht('You must give a reason for your request.')); - } - } - - public function renderHelpForArcanist() { - $text = pht( - 'Fully explain why you are requesting this code be included '. - 'in the next release.')."\n"; - return phutil_console_wrap($text, 8); - } - - public function shouldAppearOnCommitMessage() { - return true; - } - - public function renderLabelForCommitMessage() { - return pht('Request Reason'); - } - - public function renderValueForCommitMessage() { - return $this->getValue(); - } - - public function shouldMarkup() { - return true; - } - - public function getMarkupText($field) { - $reason = $this->getValue(); - if ($reason) { - return $reason; - } else { - return ''; - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephRequestorFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephRequestorFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephRequestorFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephRequestorFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -<?php - -final class ReleephRequestorFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'requestor'; - } - - public function getName() { - return pht('Requestor'); - } - - public function getRequiredHandlePHIDsForPropertyView() { - $phids = array(); - - $phid = $this->getReleephRequest()->getRequestUserPHID(); - if ($phid) { - $phids[] = $phid; - } - - return $phids; - } - - public function renderPropertyViewValue(array $handles) { - return $this->renderHandleList($handles); - } - - public function shouldAppearOnCommitMessage() { - return true; - } - - public function shouldAppearOnRevertMessage() { - return true; - } - - public function renderLabelForCommitMessage() { - return pht('Requested By'); - } - - public function renderValueForCommitMessage() { - $phid = $this->getReleephRequest()->getRequestUserPHID(); - $handle = id(new PhabricatorHandleQuery()) - ->setViewer($this->getUser()) - ->withPHIDs(array($phid)) - ->executeOne(); - return $handle->getName(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephRevisionFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -<?php - -final class ReleephRevisionFieldSpecification - extends ReleephFieldSpecification { - - public function getFieldKey() { - return 'revision'; - } - - public function getName() { - return pht('Revision'); - } - - public function getRequiredHandlePHIDsForPropertyView() { - $requested_object = $this->getObject()->getRequestedObjectPHID(); - if (!($requested_object instanceof DifferentialRevision)) { - return array(); - } - - return array( - $requested_object->getPHID(), - ); - } - - public function renderPropertyViewValue(array $handles) { - return $this->renderHandleList($handles); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephSeverityFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephSeverityFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephSeverityFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephSeverityFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -<?php - -final class ReleephSeverityFieldSpecification - extends ReleephLevelFieldSpecification { - - const HOTFIX = 'HOTFIX'; - const RELEASE = 'RELEASE'; - - public function getFieldKey() { - return 'severity'; - } - - public function getName() { - return pht('Severity'); - } - - public function getStorageKey() { - return 'releeph:severity'; - } - - public function getLevels() { - return array( - self::HOTFIX, - self::RELEASE, - ); - } - - public function getDefaultLevel() { - return self::RELEASE; - } - - public function getNameForLevel($level) { - static $names = array( - self::HOTFIX => 'HOTFIX', - self::RELEASE => 'RELEASE', - ); - return idx($names, $level, $level); - } - - public function getDescriptionForLevel($level) { - static $descriptions; - - if ($descriptions === null) { - $descriptions = array( - self::HOTFIX => pht('Needs merging and fixing right now.'), - self::RELEASE => pht('Required for the currently rolling release.'), - ); - } - - return idx($descriptions, $level); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephSummaryFieldSpecification.php phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephSummaryFieldSpecification.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/field/specification/ReleephSummaryFieldSpecification.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/field/specification/ReleephSummaryFieldSpecification.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -<?php - -final class ReleephSummaryFieldSpecification - extends ReleephFieldSpecification { - - const MAX_SUMMARY_LENGTH = 60; - - public function shouldAppearInPropertyView() { - return false; - } - - public function getFieldKey() { - return 'summary'; - } - - public function getName() { - return pht('Summary'); - } - - public function getStorageKey() { - return 'summary'; - } - - private $error = false; - - public function renderEditControl(array $handles) { - return id(new AphrontFormTextControl()) - ->setLabel(pht('Summary')) - ->setName('summary') - ->setError($this->error) - ->setValue($this->getValue()) - ->setCaption(pht('Leave this blank to use the original commit title')); - } - - public function renderHelpForArcanist() { - $text = pht( - 'A one-line title summarizing this request. '. - 'Leave blank to use the original commit title.')."\n"; - return phutil_console_wrap($text, 8); - } - - public function validate($summary) { - if ($summary && strlen($summary) > self::MAX_SUMMARY_LENGTH) { - $this->error = pht('Too long!'); - throw new ReleephFieldParseException( - $this, - pht( - 'Please keep your summary to under %d characters.', - self::MAX_SUMMARY_LENGTH)); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/mail/ReleephRequestMailReceiver.php phabricator-0~git20220903/phabricator/src/applications/releeph/mail/ReleephRequestMailReceiver.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/mail/ReleephRequestMailReceiver.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/mail/ReleephRequestMailReceiver.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -<?php - -final class ReleephRequestMailReceiver extends PhabricatorObjectMailReceiver { - - public function isEnabled() { - $app_class = 'PhabricatorReleephApplication'; - return PhabricatorApplication::isClassInstalled($app_class); - } - - protected function getObjectPattern() { - return 'Y[1-9]\d*'; - } - - protected function loadObject($pattern, PhabricatorUser $viewer) { - $id = (int)substr($pattern, 1); - - return id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - } - - protected function getTransactionReplyHandler() { - return new ReleephRequestReplyHandler(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/mail/ReleephRequestReplyHandler.php phabricator-0~git20220903/phabricator/src/applications/releeph/mail/ReleephRequestReplyHandler.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/mail/ReleephRequestReplyHandler.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/mail/ReleephRequestReplyHandler.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -<?php - -final class ReleephRequestReplyHandler - extends PhabricatorApplicationTransactionReplyHandler { - - public function validateMailReceiver($mail_receiver) { - if (!($mail_receiver instanceof ReleephRequest)) { - throw new Exception(pht('Mail receiver is not a %s!', 'ReleephRequest')); - } - } - - public function getObjectPrefix() { - return 'Y'; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/phid/ReleephBranchPHIDType.php phabricator-0~git20220903/phabricator/src/applications/releeph/phid/ReleephBranchPHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/phid/ReleephBranchPHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/phid/ReleephBranchPHIDType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -<?php - -final class ReleephBranchPHIDType extends PhabricatorPHIDType { - - const TYPECONST = 'REBR'; - - public function getTypeName() { - return pht('Releeph Branch'); - } - - public function newObject() { - return new ReleephBranch(); - } - - public function getPHIDTypeApplicationClass() { - return 'PhabricatorReleephApplication'; - } - - protected function buildQueryForObjects( - PhabricatorObjectQuery $query, - array $phids) { - - return id(new ReleephBranchQuery()) - ->withPHIDs($phids); - } - - public function loadHandles( - PhabricatorHandleQuery $query, - array $handles, - array $objects) { - - foreach ($handles as $phid => $handle) { - $branch = $objects[$phid]; - - $handle->setURI($branch->getURI()); - $handle->setName($branch->getBasename()); - $handle->setFullName($branch->getName()); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/phid/ReleephProductPHIDType.php phabricator-0~git20220903/phabricator/src/applications/releeph/phid/ReleephProductPHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/phid/ReleephProductPHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/phid/ReleephProductPHIDType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -<?php - -final class ReleephProductPHIDType extends PhabricatorPHIDType { - - const TYPECONST = 'REPR'; - - public function getTypeName() { - return pht('Releeph Product'); - } - - public function newObject() { - return new ReleephProject(); - } - - public function getPHIDTypeApplicationClass() { - return 'PhabricatorReleephApplication'; - } - - protected function buildQueryForObjects( - PhabricatorObjectQuery $query, - array $phids) { - - return id(new ReleephProductQuery()) - ->withPHIDs($phids); - } - - public function loadHandles( - PhabricatorHandleQuery $query, - array $handles, - array $objects) { - - foreach ($handles as $phid => $handle) { - $product = $objects[$phid]; - - $handle->setName($product->getName()); - $handle->setURI($product->getURI()); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/phid/ReleephRequestPHIDType.php phabricator-0~git20220903/phabricator/src/applications/releeph/phid/ReleephRequestPHIDType.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/phid/ReleephRequestPHIDType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/phid/ReleephRequestPHIDType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -<?php - -final class ReleephRequestPHIDType extends PhabricatorPHIDType { - - const TYPECONST = 'RERQ'; - - public function getTypeName() { - return pht('Releeph Request'); - } - - public function newObject() { - return new ReleephRequest(); - } - - public function getPHIDTypeApplicationClass() { - return 'PhabricatorReleephApplication'; - } - - protected function buildQueryForObjects( - PhabricatorObjectQuery $query, - array $phids) { - - return id(new ReleephRequestQuery()) - ->withPHIDs($phids); - } - - public function loadHandles( - PhabricatorHandleQuery $query, - array $handles, - array $objects) { - - foreach ($handles as $phid => $handle) { - $request = $objects[$phid]; - - $id = $request->getID(); - $title = $request->getSummaryForDisplay(); - - $handle->setURI("/RQ{$id}"); - $handle->setName($title); - $handle->setFullName("RQ{$id}: {$title}"); - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephBranchQuery.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephBranchQuery.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephBranchQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephBranchQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,152 +0,0 @@ -<?php - -final class ReleephBranchQuery - extends PhabricatorCursorPagedPolicyAwareQuery { - - private $ids; - private $phids; - private $productPHIDs; - private $productIDs; - - const STATUS_ALL = 'status-all'; - const STATUS_OPEN = 'status-open'; - private $status = self::STATUS_ALL; - - private $needCutPointCommits; - - public function withIDs(array $ids) { - $this->ids = $ids; - return $this; - } - - public function withPHIDs(array $phids) { - $this->phids = $phids; - return $this; - } - - public function needCutPointCommits($need_commits) { - $this->needCutPointCommits = $need_commits; - return $this; - } - - public function withStatus($status) { - $this->status = $status; - return $this; - } - - public function withProductPHIDs($product_phids) { - $this->productPHIDs = $product_phids; - return $this; - } - - protected function loadPage() { - $table = new ReleephBranch(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); - } - - protected function willExecute() { - if ($this->productPHIDs !== null) { - $products = id(new ReleephProductQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($this->productPHIDs) - ->execute(); - - if (!$products) { - throw new PhabricatorEmptyQueryException(); - } - - $this->productIDs = mpull($products, 'getID'); - } - } - - protected function willFilterPage(array $branches) { - $project_ids = mpull($branches, 'getReleephProjectID'); - - $projects = id(new ReleephProductQuery()) - ->withIDs($project_ids) - ->setViewer($this->getViewer()) - ->execute(); - - foreach ($branches as $key => $branch) { - $project_id = $project_ids[$key]; - if (isset($projects[$project_id])) { - $branch->attachProject($projects[$project_id]); - } else { - unset($branches[$key]); - } - } - - if ($this->needCutPointCommits) { - $commit_phids = mpull($branches, 'getCutPointCommitPHID'); - $commits = id(new DiffusionCommitQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($commit_phids) - ->execute(); - $commits = mpull($commits, null, 'getPHID'); - - foreach ($branches as $branch) { - $commit = idx($commits, $branch->getCutPointCommitPHID()); - $branch->attachCutPointCommit($commit); - } - } - - return $branches; - } - - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); - - if ($this->ids !== null) { - $where[] = qsprintf( - $conn, - 'id IN (%Ld)', - $this->ids); - } - - if ($this->phids !== null) { - $where[] = qsprintf( - $conn, - 'phid IN (%Ls)', - $this->phids); - } - - if ($this->productIDs !== null) { - $where[] = qsprintf( - $conn, - 'releephProjectID IN (%Ld)', - $this->productIDs); - } - - $status = $this->status; - switch ($status) { - case self::STATUS_ALL: - break; - case self::STATUS_OPEN: - $where[] = qsprintf( - $conn, - 'isActive = 1'); - break; - default: - throw new Exception(pht("Unknown status constant '%s'!", $status)); - } - - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); - } - - public function getQueryApplicationClass() { - return 'PhabricatorReleephApplication'; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephBranchSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephBranchSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephBranchSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephBranchSearchEngine.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,200 +0,0 @@ -<?php - -final class ReleephBranchSearchEngine - extends PhabricatorApplicationSearchEngine { - - private $product; - - public function getResultTypeDescription() { - return pht('Releeph Branches'); - } - - public function canUseInPanelContext() { - return false; - } - - public function getApplicationClassName() { - return 'PhabricatorReleephApplication'; - } - - public function setProduct(ReleephProject $product) { - $this->product = $product; - return $this; - } - - public function getProduct() { - return $this->product; - } - - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - $saved->setParameter('active', $request->getStr('active')); - - return $saved; - } - - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new ReleephBranchQuery()) - ->needCutPointCommits(true) - ->withProductPHIDs(array($this->getProduct()->getPHID())); - - $active = $saved->getParameter('active'); - $value = idx($this->getActiveValues(), $active); - if ($value !== null) { - $query->withStatus($value); - } - - return $query; - } - - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { - - $form->appendChild( - id(new AphrontFormSelectControl()) - ->setName('active') - ->setLabel(pht('Show Branches')) - ->setValue($saved_query->getParameter('active')) - ->setOptions($this->getActiveOptions())); - } - - protected function getURI($path) { - return '/releeph/product/'.$this->getProduct()->getID().'/'.$path; - } - - protected function getBuiltinQueryNames() { - $names = array( - 'open' => pht('Open'), - 'all' => pht('All'), - ); - - return $names; - } - - public function buildSavedQueryFromBuiltin($query_key) { - - $query = $this->newSavedQuery(); - $query->setQueryKey($query_key); - - switch ($query_key) { - case 'open': - return $query - ->setParameter('active', 'open'); - case 'all': - return $query; - } - - return parent::buildSavedQueryFromBuiltin($query_key); - } - - private function getActiveOptions() { - return array( - 'open' => pht('Open Branches'), - 'all' => pht('Open and Closed Branches'), - ); - } - - private function getActiveValues() { - return array( - 'open' => ReleephBranchQuery::STATUS_OPEN, - 'all' => ReleephBranchQuery::STATUS_ALL, - ); - } - - protected function renderResultList( - array $branches, - PhabricatorSavedQuery $query, - array $handles) { - - - assert_instances_of($branches, 'ReleephBranch'); - - $viewer = $this->getRequest()->getUser(); - - $products = mpull($branches, 'getProduct'); - $repo_phids = mpull($products, 'getRepositoryPHID'); - - if ($repo_phids) { - $repos = id(new PhabricatorRepositoryQuery()) - ->setViewer($viewer) - ->withPHIDs($repo_phids) - ->execute(); - $repos = mpull($repos, null, 'getPHID'); - } else { - $repos = array(); - } - - $requests = array(); - if ($branches) { - $requests = id(new ReleephRequestQuery()) - ->setViewer($viewer) - ->withBranchIDs(mpull($branches, 'getID')) - ->withStatus(ReleephRequestQuery::STATUS_OPEN) - ->execute(); - $requests = mgroup($requests, 'getBranchID'); - } - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - foreach ($branches as $branch) { - $diffusion_href = null; - $repo = idx($repos, $branch->getProduct()->getRepositoryPHID()); - if ($repo) { - $drequest = DiffusionRequest::newFromDictionary( - array( - 'user' => $viewer, - 'repository' => $repo, - )); - - $diffusion_href = $drequest->generateURI( - array( - 'action' => 'branch', - 'branch' => $branch->getName(), - )); - } - - $branch_link = $branch->getName(); - if ($diffusion_href) { - $branch_link = phutil_tag( - 'a', - array( - 'href' => $diffusion_href, - ), - $branch_link); - } - - $item = id(new PHUIObjectItemView()) - ->setHeader($branch->getDisplayName()) - ->setHref($this->getApplicationURI('branch/'.$branch->getID().'/')) - ->addAttribute($branch_link); - - if (!$branch->getIsActive()) { - $item->setDisabled(true); - } - - $commit = $branch->getCutPointCommit(); - if ($commit) { - $item->addIcon( - 'none', - phabricator_datetime($commit->getEpoch(), $viewer)); - } - - $open_count = count(idx($requests, $branch->getID(), array())); - if ($open_count) { - $item->setStatusIcon('fa-code-fork orange'); - $item->addIcon( - 'fa-code-fork', - pht( - '%s Open Pull Request(s)', - new PhutilNumber($open_count))); - } - - $list->addItem($item); - } - - return id(new PhabricatorApplicationSearchResultView()) - ->setObjectList($list); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephBranchTransactionQuery.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephBranchTransactionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephBranchTransactionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephBranchTransactionQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -<?php - -final class ReleephBranchTransactionQuery - extends PhabricatorApplicationTransactionQuery { - - public function getTemplateApplicationTransaction() { - return new ReleephBranchTransaction(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephProductQuery.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephProductQuery.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephProductQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephProductQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,144 +0,0 @@ -<?php - -final class ReleephProductQuery - extends PhabricatorCursorPagedPolicyAwareQuery { - - private $active; - private $ids; - private $phids; - private $repositoryPHIDs; - - const ORDER_ID = 'order-id'; - const ORDER_NAME = 'order-name'; - - public function withActive($active) { - $this->active = $active; - return $this; - } - - public function setOrder($order) { - switch ($order) { - case self::ORDER_ID: - $this->setOrderVector(array('id')); - break; - case self::ORDER_NAME: - $this->setOrderVector(array('name')); - break; - default: - throw new Exception(pht('Order "%s" not supported.', $order)); - } - return $this; - } - - public function withIDs(array $ids) { - $this->ids = $ids; - return $this; - } - - public function withPHIDs(array $phids) { - $this->phids = $phids; - return $this; - } - - public function withRepositoryPHIDs(array $repository_phids) { - $this->repositoryPHIDs = $repository_phids; - return $this; - } - - protected function loadPage() { - $table = new ReleephProject(); - $conn_r = $table->establishConnection('r'); - - $rows = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($rows); - } - - protected function willFilterPage(array $projects) { - assert_instances_of($projects, 'ReleephProject'); - - $repository_phids = mpull($projects, 'getRepositoryPHID'); - - $repositories = id(new PhabricatorRepositoryQuery()) - ->setViewer($this->getViewer()) - ->withPHIDs($repository_phids) - ->execute(); - $repositories = mpull($repositories, null, 'getPHID'); - - foreach ($projects as $key => $project) { - $repo = idx($repositories, $project->getRepositoryPHID()); - if (!$repo) { - unset($projects[$key]); - continue; - } - $project->attachRepository($repo); - } - - return $projects; - } - - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); - - if ($this->active !== null) { - $where[] = qsprintf( - $conn, - 'isActive = %d', - (int)$this->active); - } - - if ($this->ids !== null) { - $where[] = qsprintf( - $conn, - 'id IN (%Ls)', - $this->ids); - } - - if ($this->phids !== null) { - $where[] = qsprintf( - $conn, - 'phid IN (%Ls)', - $this->phids); - } - - if ($this->repositoryPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'repositoryPHID IN (%Ls)', - $this->repositoryPHIDs); - } - - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); - } - - public function getOrderableColumns() { - return parent::getOrderableColumns() + array( - 'name' => array( - 'column' => 'name', - 'unique' => true, - 'reverse' => true, - 'type' => 'string', - ), - ); - } - - protected function newPagingMapFromPartialObject($object) { - return array( - 'id' => (int)$object->getID(), - 'name' => $object->getName(), - ); - } - - public function getQueryApplicationClass() { - return 'PhabricatorReleephApplication'; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephProductSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephProductSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephProductSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephProductSearchEngine.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -<?php - -final class ReleephProductSearchEngine - extends PhabricatorApplicationSearchEngine { - - public function getResultTypeDescription() { - return pht('Releeph Products'); - } - - public function getApplicationClassName() { - return 'PhabricatorReleephApplication'; - } - - public function canUseInPanelContext() { - return false; - } - - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - $saved->setParameter('active', $request->getStr('active')); - - return $saved; - } - - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new ReleephProductQuery()) - ->setOrder(ReleephProductQuery::ORDER_NAME); - - $active = $saved->getParameter('active'); - $value = idx($this->getActiveValues(), $active); - if ($value !== null) { - $query->withActive($value); - } - - return $query; - } - - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { - - $form->appendChild( - id(new AphrontFormSelectControl()) - ->setName('active') - ->setLabel(pht('Show Products')) - ->setValue($saved_query->getParameter('active')) - ->setOptions($this->getActiveOptions())); - } - - protected function getURI($path) { - return '/releeph/project/'.$path; - } - - protected function getBuiltinQueryNames() { - return array( - 'active' => pht('Active'), - 'all' => pht('All'), - ); - } - - public function buildSavedQueryFromBuiltin($query_key) { - $query = $this->newSavedQuery(); - $query->setQueryKey($query_key); - - switch ($query_key) { - case 'active': - return $query - ->setParameter('active', 'active'); - case 'all': - return $query; - } - - return parent::buildSavedQueryFromBuiltin($query_key); - } - - private function getActiveOptions() { - return array( - 'all' => pht('Active and Inactive Products'), - 'active' => pht('Active Products'), - 'inactive' => pht('Inactive Products'), - ); - } - - private function getActiveValues() { - return array( - 'all' => null, - 'active' => 1, - 'inactive' => 0, - ); - } - - protected function renderResultList( - array $products, - PhabricatorSavedQuery $query, - array $handles) { - - assert_instances_of($products, 'ReleephProject'); - $viewer = $this->requireViewer(); - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - - foreach ($products as $product) { - $id = $product->getID(); - - $item = id(new PHUIObjectItemView()) - ->setHeader($product->getName()) - ->setHref($this->getApplicationURI("product/{$id}/")); - - if (!$product->getIsActive()) { - $item->setDisabled(true); - $item->addIcon('none', pht('Inactive')); - } - - $repo = $product->getRepository(); - $item->addAttribute( - phutil_tag( - 'a', - array( - 'href' => $repo->getURI(), - ), - $repo->getMonogram())); - - $list->addItem($item); - } - - $result = new PhabricatorApplicationSearchResultView(); - $result->setObjectList($list); - - return $result; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephProductTransactionQuery.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephProductTransactionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephProductTransactionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephProductTransactionQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -<?php - -final class ReleephProductTransactionQuery - extends PhabricatorApplicationTransactionQuery { - - public function getTemplateApplicationTransaction() { - return new ReleephProductTransaction(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephRequestQuery.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephRequestQuery.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephRequestQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephRequestQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -<?php - -final class ReleephRequestQuery - extends PhabricatorCursorPagedPolicyAwareQuery { - - private $requestedCommitPHIDs; - private $ids; - private $phids; - private $severities; - private $requestorPHIDs; - private $branchIDs; - private $requestedObjectPHIDs; - - const STATUS_ALL = 'status-all'; - const STATUS_OPEN = 'status-open'; - const STATUS_REQUESTED = 'status-requested'; - const STATUS_NEEDS_PULL = 'status-needs-pull'; - const STATUS_REJECTED = 'status-rejected'; - const STATUS_ABANDONED = 'status-abandoned'; - const STATUS_PULLED = 'status-pulled'; - const STATUS_NEEDS_REVERT = 'status-needs-revert'; - const STATUS_REVERTED = 'status-reverted'; - - private $status = self::STATUS_ALL; - - public function withIDs(array $ids) { - $this->ids = $ids; - return $this; - } - - public function withPHIDs(array $phids) { - $this->phids = $phids; - return $this; - } - - public function withBranchIDs(array $branch_ids) { - $this->branchIDs = $branch_ids; - return $this; - } - - public function withStatus($status) { - $this->status = $status; - return $this; - } - - public function withRequestedCommitPHIDs(array $requested_commit_phids) { - $this->requestedCommitPHIDs = $requested_commit_phids; - return $this; - } - - public function withRequestorPHIDs(array $phids) { - $this->requestorPHIDs = $phids; - return $this; - } - - public function withSeverities(array $severities) { - $this->severities = $severities; - return $this; - } - - public function withRequestedObjectPHIDs(array $phids) { - $this->requestedObjectPHIDs = $phids; - return $this; - } - - protected function loadPage() { - $table = new ReleephRequest(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); - } - - protected function willFilterPage(array $requests) { - // Load requested objects: you must be able to see an object to see - // requests for it. - $object_phids = mpull($requests, 'getRequestedObjectPHID'); - $objects = id(new PhabricatorObjectQuery()) - ->setViewer($this->getViewer()) - ->setParentQuery($this) - ->withPHIDs($object_phids) - ->execute(); - - foreach ($requests as $key => $request) { - $object_phid = $request->getRequestedObjectPHID(); - $object = idx($objects, $object_phid); - if (!$object) { - unset($requests[$key]); - continue; - } - $request->attachRequestedObject($object); - } - - if ($this->severities) { - $severities = array_fuse($this->severities); - foreach ($requests as $key => $request) { - - // NOTE: Facebook uses a custom field here. - if (ReleephDefaultFieldSelector::isFacebook()) { - $severity = $request->getDetail('severity'); - } else { - $severity = $request->getDetail('releeph:severity'); - } - - if (empty($severities[$severity])) { - unset($requests[$key]); - } - } - } - - $branch_ids = array_unique(mpull($requests, 'getBranchID')); - $branches = id(new ReleephBranchQuery()) - ->withIDs($branch_ids) - ->setViewer($this->getViewer()) - ->execute(); - $branches = mpull($branches, null, 'getID'); - foreach ($requests as $key => $request) { - $branch = idx($branches, $request->getBranchID()); - if (!$branch) { - unset($requests[$key]); - continue; - } - $request->attachBranch($branch); - } - - // TODO: These should be serviced by the query, but are not currently - // denormalized anywhere. For now, filter them here instead. Note that - // we must perform this filtering *after* querying and attaching branches, - // because request status depends on the product. - - $keep_status = array_fuse($this->getKeepStatusConstants()); - if ($keep_status) { - foreach ($requests as $key => $request) { - if (empty($keep_status[$request->getStatus()])) { - unset($requests[$key]); - } - } - } - - return $requests; - } - - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); - - if ($this->ids !== null) { - $where[] = qsprintf( - $conn, - 'id IN (%Ld)', - $this->ids); - } - - if ($this->phids !== null) { - $where[] = qsprintf( - $conn, - 'phid IN (%Ls)', - $this->phids); - } - - if ($this->branchIDs !== null) { - $where[] = qsprintf( - $conn, - 'branchID IN (%Ld)', - $this->branchIDs); - } - - if ($this->requestedCommitPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'requestCommitPHID IN (%Ls)', - $this->requestedCommitPHIDs); - } - - if ($this->requestorPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'requestUserPHID IN (%Ls)', - $this->requestorPHIDs); - } - - if ($this->requestedObjectPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'requestedObjectPHID IN (%Ls)', - $this->requestedObjectPHIDs); - } - - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); - } - - private function getKeepStatusConstants() { - switch ($this->status) { - case self::STATUS_ALL: - return array(); - case self::STATUS_OPEN: - return array( - ReleephRequestStatus::STATUS_REQUESTED, - ReleephRequestStatus::STATUS_NEEDS_PICK, - ReleephRequestStatus::STATUS_NEEDS_REVERT, - ); - case self::STATUS_REQUESTED: - return array( - ReleephRequestStatus::STATUS_REQUESTED, - ); - case self::STATUS_NEEDS_PULL: - return array( - ReleephRequestStatus::STATUS_NEEDS_PICK, - ); - case self::STATUS_REJECTED: - return array( - ReleephRequestStatus::STATUS_REJECTED, - ); - case self::STATUS_ABANDONED: - return array( - ReleephRequestStatus::STATUS_ABANDONED, - ); - case self::STATUS_PULLED: - return array( - ReleephRequestStatus::STATUS_PICKED, - ); - case self::STATUS_NEEDS_REVERT: - return array( - ReleephRequestStatus::STATUS_NEEDS_REVERT, - ); - case self::STATUS_REVERTED: - return array( - ReleephRequestStatus::STATUS_REVERTED, - ); - default: - throw new Exception(pht("Unknown status '%s'!", $this->status)); - } - } - - public function getQueryApplicationClass() { - return 'PhabricatorReleephApplication'; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephRequestSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephRequestSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephRequestSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephRequestSearchEngine.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -<?php - -final class ReleephRequestSearchEngine - extends PhabricatorApplicationSearchEngine { - - private $branch; - private $baseURI; - - public function getResultTypeDescription() { - return pht('Releeph Pull Requests'); - } - - public function getApplicationClassName() { - return 'PhabricatorReleephApplication'; - } - - public function canUseInPanelContext() { - return false; - } - - public function setBranch(ReleephBranch $branch) { - $this->branch = $branch; - return $this; - } - - public function getBranch() { - return $this->branch; - } - - public function setBaseURI($base_uri) { - $this->baseURI = $base_uri; - return $this; - } - - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - $saved->setParameter('status', $request->getStr('status')); - $saved->setParameter('severity', $request->getStr('severity')); - $saved->setParameter( - 'requestorPHIDs', - $this->readUsersFromRequest($request, 'requestors')); - - return $saved; - } - - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new ReleephRequestQuery()) - ->withBranchIDs(array($this->getBranch()->getID())); - - $status = $saved->getParameter('status'); - $status = idx($this->getStatusValues(), $status); - if ($status) { - $query->withStatus($status); - } - - $severity = $saved->getParameter('severity'); - if ($severity) { - $query->withSeverities(array($severity)); - } - - $requestor_phids = $saved->getParameter('requestorPHIDs'); - if ($requestor_phids) { - $query->withRequestorPHIDs($requestor_phids); - } - - return $query; - } - - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { - - $requestor_phids = $saved_query->getParameter('requestorPHIDs', array()); - - $form - ->appendChild( - id(new AphrontFormSelectControl()) - ->setName('status') - ->setLabel(pht('Status')) - ->setValue($saved_query->getParameter('status')) - ->setOptions($this->getStatusOptions())) - ->appendChild( - id(new AphrontFormSelectControl()) - ->setName('severity') - ->setLabel(pht('Severity')) - ->setValue($saved_query->getParameter('severity')) - ->setOptions($this->getSeverityOptions())) - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setName('requestors') - ->setLabel(pht('Requestors')) - ->setValue($requestor_phids)); - } - - protected function getURI($path) { - return $this->baseURI.$path; - } - - protected function getBuiltinQueryNames() { - $names = array( - 'open' => pht('Open Requests'), - 'all' => pht('All Requests'), - ); - - if ($this->requireViewer()->isLoggedIn()) { - $names['requested'] = pht('Requested'); - } - - return $names; - } - - public function buildSavedQueryFromBuiltin($query_key) { - - $query = $this->newSavedQuery(); - $query->setQueryKey($query_key); - - switch ($query_key) { - case 'open': - return $query->setParameter('status', 'open'); - case 'all': - return $query; - case 'requested': - return $query->setParameter( - 'requestorPHIDs', - array($this->requireViewer()->getPHID())); - } - - return parent::buildSavedQueryFromBuiltin($query_key); - } - - private function getStatusOptions() { - return array( - '' => pht('(All Requests)'), - 'open' => pht('Open Requests'), - 'requested' => pht('Pull Requested'), - 'needs-pull' => pht('Needs Pull'), - 'rejected' => pht('Rejected'), - 'abandoned' => pht('Abandoned'), - 'pulled' => pht('Pulled'), - 'needs-revert' => pht('Needs Revert'), - 'reverted' => pht('Reverted'), - ); - } - - private function getStatusValues() { - return array( - 'open' => ReleephRequestQuery::STATUS_OPEN, - 'requested' => ReleephRequestQuery::STATUS_REQUESTED, - 'needs-pull' => ReleephRequestQuery::STATUS_NEEDS_PULL, - 'rejected' => ReleephRequestQuery::STATUS_REJECTED, - 'abandoned' => ReleephRequestQuery::STATUS_ABANDONED, - 'pulled' => ReleephRequestQuery::STATUS_PULLED, - 'needs-revert' => ReleephRequestQuery::STATUS_NEEDS_REVERT, - 'reverted' => ReleephRequestQuery::STATUS_REVERTED, - ); - } - - private function getSeverityOptions() { - if (ReleephDefaultFieldSelector::isFacebook()) { - return array( - '' => pht('(All Severities)'), - 11 => pht('HOTFIX'), - 12 => pht('PIGGYBACK'), - 13 => pht('RELEASE'), - 14 => pht('DAILY'), - 15 => pht('PARKING'), - ); - } else { - return array( - '' => pht('(All Severities)'), - ReleephSeverityFieldSpecification::HOTFIX => pht('Hotfix'), - ReleephSeverityFieldSpecification::RELEASE => pht('Release'), - ); - } - } - - protected function renderResultList( - array $requests, - PhabricatorSavedQuery $query, - array $handles) { - - assert_instances_of($requests, 'ReleephRequest'); - $viewer = $this->requireViewer(); - - // TODO: This is generally a bit sketchy, but we don't do this kind of - // thing elsewhere at the moment. For the moment it shouldn't be hugely - // costly, and we can batch things later. Generally, this commits fewer - // sins than the old code did. - - $engine = id(new PhabricatorMarkupEngine()) - ->setViewer($viewer); - - $list = array(); - foreach ($requests as $pull) { - $field_list = PhabricatorCustomField::getObjectFields( - $pull, - PhabricatorCustomField::ROLE_VIEW); - - $field_list - ->setViewer($viewer) - ->readFieldsFromStorage($pull); - - foreach ($field_list->getFields() as $field) { - if ($field->shouldMarkup()) { - $field->setMarkupEngine($engine); - } - } - - $list[] = id(new ReleephRequestView()) - ->setUser($viewer) - ->setCustomFields($field_list) - ->setPullRequest($pull) - ->setIsListView(true); - } - - // This is quite sketchy, but the list has not actually rendered yet, so - // this still allows us to batch the markup rendering. - $engine->process(); - - return id(new PhabricatorApplicationSearchResultView()) - ->setContent($list); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephRequestTransactionQuery.php phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephRequestTransactionQuery.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/query/ReleephRequestTransactionQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/query/ReleephRequestTransactionQuery.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -<?php - -final class ReleephRequestTransactionQuery - extends PhabricatorApplicationTransactionQuery { - - public function getTemplateApplicationTransaction() { - return new ReleephRequestTransaction(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephBranch.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephBranch.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephBranch.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephBranch.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,188 +0,0 @@ -<?php - -final class ReleephBranch extends ReleephDAO - implements - PhabricatorApplicationTransactionInterface, - PhabricatorPolicyInterface { - - protected $releephProjectID; - protected $isActive; - protected $createdByUserPHID; - - // The immutable name of this branch ('releases/foo-2013.01.24') - protected $name; - protected $basename; - - // The symbolic name of this branch (LATEST, PRODUCTION, RC, ...) - // See SYMBOLIC_NAME_NOTE below - protected $symbolicName; - - // Where to cut the branch - protected $cutPointCommitPHID; - - protected $details = array(); - - private $project = self::ATTACHABLE; - private $cutPointCommit = self::ATTACHABLE; - - protected function getConfiguration() { - return array( - self::CONFIG_AUX_PHID => true, - self::CONFIG_SERIALIZATION => array( - 'details' => self::SERIALIZATION_JSON, - ), - self::CONFIG_COLUMN_SCHEMA => array( - 'basename' => 'text64', - 'isActive' => 'bool', - 'symbolicName' => 'text64?', - 'name' => 'text128', - ), - self::CONFIG_KEY_SCHEMA => array( - 'releephProjectID' => array( - 'columns' => array('releephProjectID', 'symbolicName'), - 'unique' => true, - ), - 'releephProjectID_2' => array( - 'columns' => array('releephProjectID', 'basename'), - 'unique' => true, - ), - 'releephProjectID_name' => array( - 'columns' => array('releephProjectID', 'name'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function generatePHID() { - return PhabricatorPHID::generateNewPHID(ReleephBranchPHIDType::TYPECONST); - } - - public function getDetail($key, $default = null) { - return idx($this->getDetails(), $key, $default); - } - - public function setDetail($key, $value) { - $this->details[$key] = $value; - return $this; - } - - protected function willWriteData(array &$data) { - // If symbolicName is omitted, set it to the basename. - // - // This means that we can enforce symbolicName as a UNIQUE column in the - // DB. We'll interpret symbolicName === basename as meaning "no symbolic - // name". - // - // SYMBOLIC_NAME_NOTE - if (!$data['symbolicName']) { - $data['symbolicName'] = $data['basename']; - } - parent::willWriteData($data); - } - - public function getSymbolicName() { - // See SYMBOLIC_NAME_NOTE above for why this is needed - if ($this->symbolicName == $this->getBasename()) { - return ''; - } - return $this->symbolicName; - } - - public function setSymbolicName($name) { - if ($name) { - parent::setSymbolicName($name); - } else { - parent::setSymbolicName($this->getBasename()); - } - return $this; - } - - public function getDisplayName() { - if ($sn = $this->getSymbolicName()) { - return $sn; - } - return $this->getBasename(); - } - - public function getDisplayNameWithDetail() { - $n = $this->getBasename(); - if ($sn = $this->getSymbolicName()) { - return "{$sn} ({$n})"; - } else { - return $n; - } - } - - public function getURI($path = null) { - $components = array( - '/releeph/branch', - $this->getID(), - $path, - ); - return implode('/', $components); - } - - public function isActive() { - return $this->getIsActive(); - } - - public function attachProject(ReleephProject $project) { - $this->project = $project; - return $this; - } - - public function getProject() { - return $this->assertAttached($this->project); - } - - public function getProduct() { - return $this->getProject(); - } - - public function attachCutPointCommit( - PhabricatorRepositoryCommit $commit = null) { - $this->cutPointCommit = $commit; - return $this; - } - - public function getCutPointCommit() { - return $this->assertAttached($this->cutPointCommit); - } - - -/* -( PhabricatorApplicationTransactionInterface )------------------------- */ - - - public function getApplicationTransactionEditor() { - return new ReleephBranchEditor(); - } - - public function getApplicationTransactionTemplate() { - return new ReleephBranchTransaction(); - } - - -/* -( PhabricatorPolicyInterface )----------------------------------------- */ - - - public function getCapabilities() { - return $this->getProduct()->getCapabilities(); - } - - public function getPolicy($capability) { - return $this->getProduct()->getPolicy($capability); - } - - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - return $this->getProduct()->hasAutomaticCapability($capability, $viewer); - } - - public function describeAutomaticCapability($capability) { - return pht( - 'Release branches have the same policies as the product they are a '. - 'part of.'); - } - - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephBranchTransaction.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephBranchTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephBranchTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephBranchTransaction.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -<?php - -final class ReleephBranchTransaction - extends PhabricatorApplicationTransaction { - - public function getApplicationName() { - return 'releeph'; - } - - public function getApplicationTransactionType() { - return ReleephBranchPHIDType::TYPECONST; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephDAO.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephDAO.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephDAO.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephDAO.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -<?php - -abstract class ReleephDAO extends PhabricatorLiskDAO { - - public function getApplicationName() { - return 'releeph'; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephProductTransaction.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephProductTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephProductTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephProductTransaction.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -<?php - -final class ReleephProductTransaction - extends PhabricatorApplicationTransaction { - - const TYPE_ACTIVE = 'releeph:product:active'; - - public function getApplicationName() { - return 'releeph'; - } - - public function getApplicationTransactionType() { - return ReleephProductPHIDType::TYPECONST; - } - - public function getColor() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_ACTIVE: - if ($new) { - return 'green'; - } else { - return 'black'; - } - break; - } - - return parent::getColor(); - } - - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_ACTIVE: - if ($new) { - return 'fa-pencil'; - } else { - return 'fa-times'; - } - break; - } - - return parent::getIcon(); - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_ACTIVE: - if ($new) { - return pht( - '%s activated this product.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s deactivated this product.', - $this->renderHandleLink($author_phid)); - } - break; - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_ACTIVE: - if ($new) { - return pht( - '%s activated release product %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s deactivated release product %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - } - - return parent::getTitleForFeed(); - } - - public function getNoEffectDescription() { - switch ($this->getTransactionType()) { - case self::TYPE_ACTIVE: - return pht('The product is already in that state.'); - } - - return parent::getNoEffectDescription(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephProject.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephProject.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephProject.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephProject.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -<?php - -final class ReleephProject extends ReleephDAO - implements - PhabricatorApplicationTransactionInterface, - PhabricatorPolicyInterface { - - const DEFAULT_BRANCH_NAMESPACE = 'releeph-releases'; - const SYSTEM_AGENT_USERNAME_PREFIX = 'releeph-agent-'; - - protected $name; - - // Specifying the place to pick from is a requirement for svn, though not - // for git. It's always useful though for reasoning about what revs have - // been picked and which haven't. - protected $trunkBranch; - - protected $repositoryPHID; - protected $isActive; - protected $createdByUserPHID; - - protected $details = array(); - - private $repository = self::ATTACHABLE; - - protected function getConfiguration() { - return array( - self::CONFIG_AUX_PHID => true, - self::CONFIG_SERIALIZATION => array( - 'details' => self::SERIALIZATION_JSON, - ), - self::CONFIG_COLUMN_SCHEMA => array( - 'name' => 'text128', - 'trunkBranch' => 'text255', - 'isActive' => 'bool', - ), - self::CONFIG_KEY_SCHEMA => array( - 'projectName' => array( - 'columns' => array('name'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function generatePHID() { - return PhabricatorPHID::generateNewPHID(ReleephProductPHIDType::TYPECONST); - } - - public function getDetail($key, $default = null) { - return idx($this->details, $key, $default); - } - - public function getURI($path = null) { - $components = array( - '/releeph/product', - $this->getID(), - $path, - ); - return implode('/', $components); - } - - public function setDetail($key, $value) { - $this->details[$key] = $value; - return $this; - } - - public function getPushers() { - return $this->getDetail('pushers', array()); - } - - public function isPusher(PhabricatorUser $user) { - // TODO Deprecate this once `isPusher` is out of the Facebook codebase. - return $this->isAuthoritative($user); - } - - public function isAuthoritative(PhabricatorUser $user) { - return $this->isAuthoritativePHID($user->getPHID()); - } - - public function isAuthoritativePHID($phid) { - $pushers = $this->getPushers(); - if (!$pushers) { - return true; - } else { - return in_array($phid, $pushers); - } - } - - public function attachRepository(PhabricatorRepository $repository) { - $this->repository = $repository; - return $this; - } - - public function getRepository() { - return $this->assertAttached($this->repository); - } - - public function getReleephFieldSelector() { - return new ReleephDefaultFieldSelector(); - } - - public function isTestFile($filename) { - $test_paths = $this->getDetail('testPaths', array()); - - foreach ($test_paths as $test_path) { - if (preg_match($test_path, $filename)) { - return true; - } - } - return false; - } - - -/* -( PhabricatorApplicationTransactionInterface )------------------------- */ - - - public function getApplicationTransactionEditor() { - return new ReleephProductEditor(); - } - - public function getApplicationTransactionTemplate() { - return new ReleephProductTransaction(); - } - - -/* -( PhabricatorPolicyInterface )----------------------------------------- */ - - - public function getCapabilities() { - return array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - ); - } - - public function getPolicy($capability) { - return PhabricatorPolicies::POLICY_USER; - } - - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - return false; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephRequest.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephRequest.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephRequest.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephRequest.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,354 +0,0 @@ -<?php - -final class ReleephRequest extends ReleephDAO - implements - PhabricatorApplicationTransactionInterface, - PhabricatorPolicyInterface, - PhabricatorCustomFieldInterface { - - protected $branchID; - protected $requestUserPHID; - protected $details = array(); - protected $userIntents = array(); - protected $inBranch; - protected $pickStatus; - protected $mailKey; - - /** - * The object which is being requested. Normally this is a commit, but it - * might also be a revision. In the future, it could be a repository branch - * or an external object (like a GitHub pull request). - */ - protected $requestedObjectPHID; - - // Information about the thing being requested - protected $requestCommitPHID; - - // Information about the last commit to the releeph branch - protected $commitIdentifier; - protected $commitPHID; - - - private $customFields = self::ATTACHABLE; - private $branch = self::ATTACHABLE; - private $requestedObject = self::ATTACHABLE; - - -/* -( Constants and helper methods )--------------------------------------- */ - - const INTENT_WANT = 'want'; - const INTENT_PASS = 'pass'; - - const PICK_PENDING = 1; // old - const PICK_FAILED = 2; - const PICK_OK = 3; - const PICK_MANUAL = 4; // old - const REVERT_OK = 5; - const REVERT_FAILED = 6; - - public function shouldBeInBranch() { - return - $this->getPusherIntent() == self::INTENT_WANT && - /** - * We use "!= pass" instead of "== want" in case the requestor intent is - * not present. In other words, only revert if the requestor explicitly - * passed. - */ - $this->getRequestorIntent() != self::INTENT_PASS; - } - - /** - * Will return INTENT_WANT if any pusher wants this request, and no pusher - * passes on this request. - */ - public function getPusherIntent() { - $product = $this->getBranch()->getProduct(); - - if (!$product->getPushers()) { - return self::INTENT_WANT; - } - - $found_pusher_want = false; - foreach ($this->userIntents as $phid => $intent) { - if ($product->isAuthoritativePHID($phid)) { - if ($intent == self::INTENT_PASS) { - return self::INTENT_PASS; - } - - $found_pusher_want = true; - } - } - - if ($found_pusher_want) { - return self::INTENT_WANT; - } else { - return null; - } - } - - public function getRequestorIntent() { - return idx($this->userIntents, $this->requestUserPHID); - } - - public function getStatus() { - return $this->calculateStatus(); - } - - public function getMonogram() { - return 'Y'.$this->getID(); - } - - public function getBranch() { - return $this->assertAttached($this->branch); - } - - public function attachBranch(ReleephBranch $branch) { - $this->branch = $branch; - return $this; - } - - public function getRequestedObject() { - return $this->assertAttached($this->requestedObject); - } - - public function attachRequestedObject($object) { - $this->requestedObject = $object; - return $this; - } - - private function calculateStatus() { - if ($this->shouldBeInBranch()) { - if ($this->getInBranch()) { - return ReleephRequestStatus::STATUS_PICKED; - } else { - return ReleephRequestStatus::STATUS_NEEDS_PICK; - } - } else { - if ($this->getInBranch()) { - return ReleephRequestStatus::STATUS_NEEDS_REVERT; - } else { - $intent_pass = self::INTENT_PASS; - $intent_want = self::INTENT_WANT; - - $has_been_in_branch = $this->getCommitIdentifier(); - // Regardless of why we reverted something, always say reverted if it - // was once in the branch. - if ($has_been_in_branch) { - return ReleephRequestStatus::STATUS_REVERTED; - } else if ($this->getPusherIntent() === $intent_pass) { - // Otherwise, if it has never been in the branch, explicitly say why: - return ReleephRequestStatus::STATUS_REJECTED; - } else if ($this->getRequestorIntent() === $intent_want) { - return ReleephRequestStatus::STATUS_REQUESTED; - } else { - return ReleephRequestStatus::STATUS_ABANDONED; - } - } - } - } - - -/* -( Lisk mechanics )----------------------------------------------------- */ - - protected function getConfiguration() { - return array( - self::CONFIG_AUX_PHID => true, - self::CONFIG_SERIALIZATION => array( - 'details' => self::SERIALIZATION_JSON, - 'userIntents' => self::SERIALIZATION_JSON, - ), - self::CONFIG_COLUMN_SCHEMA => array( - 'requestCommitPHID' => 'phid?', - 'commitIdentifier' => 'text40?', - 'commitPHID' => 'phid?', - 'pickStatus' => 'uint32?', - 'inBranch' => 'bool', - 'mailKey' => 'bytes20', - 'userIntents' => 'text?', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_phid' => null, - 'phid' => array( - 'columns' => array('phid'), - 'unique' => true, - ), - 'requestIdentifierBranch' => array( - 'columns' => array('requestCommitPHID', 'branchID'), - 'unique' => true, - ), - 'branchID' => array( - 'columns' => array('branchID'), - ), - 'key_requestedObject' => array( - 'columns' => array('requestedObjectPHID'), - ), - ), - ) + parent::getConfiguration(); - } - - public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - ReleephRequestPHIDType::TYPECONST); - } - - public function save() { - if (!$this->getMailKey()) { - $this->setMailKey(Filesystem::readRandomCharacters(20)); - } - return parent::save(); - } - - -/* -( Helpful accessors )--------------------------------------------------- */ - - - public function getDetail($key, $default = null) { - return idx($this->getDetails(), $key, $default); - } - - public function setDetail($key, $value) { - $this->details[$key] = $value; - return $this; - } - - - /** - * Get the commit PHIDs this request is requesting. - * - * NOTE: For now, this always returns one PHID. - * - * @return list<phid> Commit PHIDs requested by this request. - */ - public function getCommitPHIDs() { - return array( - $this->requestCommitPHID, - ); - } - - public function getReason() { - // Backward compatibility: reason used to be called comments - $reason = $this->getDetail('reason'); - if (!$reason) { - return $this->getDetail('comments'); - } - return $reason; - } - - /** - * Allow a null summary, and fall back to the title of the commit. - */ - public function getSummaryForDisplay() { - $summary = $this->getDetail('summary'); - - if (!strlen($summary)) { - $commit = $this->loadPhabricatorRepositoryCommit(); - if ($commit) { - $summary = $commit->getSummary(); - } - } - - if (!strlen($summary)) { - $summary = pht('None'); - } - - return $summary; - } - -/* -( Loading external objects )------------------------------------------- */ - - public function loadPhabricatorRepositoryCommit() { - return id(new PhabricatorRepositoryCommit())->loadOneWhere( - 'phid = %s', - $this->getRequestCommitPHID()); - } - - public function loadPhabricatorRepositoryCommitData() { - $commit = $this->loadPhabricatorRepositoryCommit(); - if ($commit) { - return id(new PhabricatorRepositoryCommitData())->loadOneWhere( - 'commitID = %d', - $commit->getID()); - } - } - - -/* -( State change helpers )----------------------------------------------- */ - - public function setUserIntent(PhabricatorUser $user, $intent) { - $this->userIntents[$user->getPHID()] = $intent; - return $this; - } - - -/* -( Migrating to status-less ReleephRequests )--------------------------- */ - - protected function didReadData() { - if ($this->userIntents === null) { - $this->userIntents = array(); - } - } - - public function setStatus($value) { - throw new Exception(pht('`%s` is now deprecated!', 'status')); - } - -/* -( PhabricatorApplicationTransactionInterface )------------------------- */ - - - public function getApplicationTransactionEditor() { - return new ReleephRequestTransactionalEditor(); - } - - public function getApplicationTransactionTemplate() { - return new ReleephRequestTransaction(); - } - - -/* -( PhabricatorPolicyInterface )----------------------------------------- */ - - - public function getCapabilities() { - return array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - ); - } - - public function getPolicy($capability) { - return $this->getBranch()->getPolicy($capability); - } - - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { - return $this->getBranch()->hasAutomaticCapability($capability, $viewer); - } - - public function describeAutomaticCapability($capability) { - return pht( - 'Pull requests have the same policies as the branches they are '. - 'requested against.'); - } - - - -/* -( PhabricatorCustomFieldInterface )------------------------------------ */ - - - public function getCustomFieldSpecificationForRole($role) { - return PhabricatorEnv::getEnvConfig('releeph.fields'); - } - - public function getCustomFieldBaseClass() { - return 'ReleephFieldSpecification'; - } - - public function getCustomFields() { - return $this->assertAttached($this->customFields); - } - - public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { - $this->customFields = $fields; - return $this; - } - - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephRequestTransactionComment.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephRequestTransactionComment.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephRequestTransactionComment.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephRequestTransactionComment.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -<?php - -final class ReleephRequestTransactionComment - extends PhabricatorApplicationTransactionComment { - - public function getApplicationTransactionObject() { - return new ReleephRequestTransaction(); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephRequestTransaction.php phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephRequestTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/storage/ReleephRequestTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/storage/ReleephRequestTransaction.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,275 +0,0 @@ -<?php - -final class ReleephRequestTransaction - extends PhabricatorApplicationTransaction { - - const TYPE_REQUEST = 'releeph:request'; - const TYPE_USER_INTENT = 'releeph:user_intent'; - const TYPE_EDIT_FIELD = 'releeph:edit_field'; - const TYPE_PICK_STATUS = 'releeph:pick_status'; - const TYPE_COMMIT = 'releeph:commit'; - const TYPE_DISCOVERY = 'releeph:discovery'; - const TYPE_MANUAL_IN_BRANCH = 'releeph:manual'; - - public function getApplicationName() { - return 'releeph'; - } - - public function getApplicationTransactionType() { - return ReleephRequestPHIDType::TYPECONST; - } - - public function getApplicationTransactionCommentObject() { - return new ReleephRequestTransactionComment(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - default; - break; - } - return parent::hasChangeDetails(); - } - - public function getRequiredHandlePHIDs() { - $phids = parent::getRequiredHandlePHIDs(); - $phids[] = $this->getObjectPHID(); - - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_REQUEST: - case self::TYPE_DISCOVERY: - $phids[] = $new; - break; - - case self::TYPE_EDIT_FIELD: - self::searchForPHIDs($this->getOldValue(), $phids); - self::searchForPHIDs($this->getNewValue(), $phids); - break; - } - - return $phids; - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_REQUEST: - return pht( - '%s requested %s', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - break; - - case self::TYPE_USER_INTENT: - return $this->getIntentTitle(); - break; - - case self::TYPE_EDIT_FIELD: - $field = newv($this->getMetadataValue('fieldClass'), array()); - $name = $field->getName(); - - $markup = $name; - if ($this->getRenderingTarget() === - parent::TARGET_HTML) { - - $markup = hsprintf('<em>%s</em>', $name); - } - - return pht( - '%s changed the %s to "%s"', - $this->renderHandleLink($author_phid), - $markup, - $field->normalizeForTransactionView($this, $new)); - break; - - case self::TYPE_PICK_STATUS: - switch ($new) { - case ReleephRequest::PICK_OK: - return pht('%s found this request picks without error', - $this->renderHandleLink($author_phid)); - - case ReleephRequest::REVERT_OK: - return pht('%s found this request reverts without error', - $this->renderHandleLink($author_phid)); - - case ReleephRequest::PICK_FAILED: - return pht("%s couldn't pick this request", - $this->renderHandleLink($author_phid)); - - case ReleephRequest::REVERT_FAILED: - return pht("%s couldn't revert this request", - $this->renderHandleLink($author_phid)); - } - break; - - case self::TYPE_COMMIT: - $action_type = $this->getMetadataValue('action'); - switch ($action_type) { - case 'pick': - return pht( - '%s picked this request and committed the result upstream', - $this->renderHandleLink($author_phid)); - break; - - case 'revert': - return pht( - '%s reverted this request and committed the result upstream', - $this->renderHandleLink($author_phid)); - break; - } - break; - - case self::TYPE_MANUAL_IN_BRANCH: - $action = $new ? pht('picked') : pht('reverted'); - return pht( - '%s marked this request as manually %s', - $this->renderHandleLink($author_phid), - $action); - break; - - case self::TYPE_DISCOVERY: - return pht('%s discovered this commit as %s', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - break; - - default: - return parent::getTitle(); - break; - } - } - - public function getActionName() { - switch ($this->getTransactionType()) { - case self::TYPE_REQUEST: - return pht('Requested'); - - case self::TYPE_COMMIT: - $action_type = $this->getMetadataValue('action'); - switch ($action_type) { - case 'pick': - return pht('Picked'); - - case 'revert': - return pht('Reverted'); - } - } - - return parent::getActionName(); - } - - public function getColor() { - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_USER_INTENT: - switch ($new) { - case ReleephRequest::INTENT_WANT: - return PhabricatorTransactions::COLOR_GREEN; - case ReleephRequest::INTENT_PASS: - return PhabricatorTransactions::COLOR_RED; - } - } - return parent::getColor(); - } - - private static function searchForPHIDs($thing, array &$phids) { - /** - * To implement something like getRequiredHandlePHIDs() in a - * ReleephFieldSpecification, we'd have to provide the field with its - * ReleephRequest (so that it could load the PHIDs from the - * ReleephRequest's storage, and return them.) - * - * We don't have fields initialized with their ReleephRequests, but we can - * make a good guess at what handles will be needed for rendering the field - * in this transaction by inspecting the old and new values. - */ - if (!is_array($thing)) { - $thing = array($thing); - } - - foreach ($thing as $value) { - if (phid_get_type($value) !== - PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { - - $phids[] = $value; - } - } - } - - private function getIntentTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $new = $this->getNewValue(); - $is_pusher = $this->getMetadataValue('isPusher'); - - switch ($new) { - case ReleephRequest::INTENT_WANT: - if ($is_pusher) { - return pht( - '%s approved this request', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s wanted this request', - $this->renderHandleLink($author_phid)); - } - - case ReleephRequest::INTENT_PASS: - if ($is_pusher) { - return pht( - '%s rejected this request', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s passed on this request', - $this->renderHandleLink($author_phid)); - } - } - } - - public function shouldHide() { - $type = $this->getTransactionType(); - - if ($type === self::TYPE_USER_INTENT && - $this->getMetadataValue('isRQCreate')) { - - return true; - } - - if ($this->isBoringPickStatus()) { - return true; - } - - // ReleephSummaryFieldSpecification is usually blank when an RQ is created, - // creating a transaction change from null to "". Hide these! - if ($type === self::TYPE_EDIT_FIELD) { - if ($this->getOldValue() === null && $this->getNewValue() === '') { - return true; - } - } - return parent::shouldHide(); - } - - public function isBoringPickStatus() { - $type = $this->getTransactionType(); - if ($type === self::TYPE_PICK_STATUS) { - $new = $this->getNewValue(); - if ($new === ReleephRequest::PICK_OK || - $new === ReleephRequest::REVERT_OK) { - - return true; - } - } - return false; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/view/branch/ReleephBranchPreviewView.php phabricator-0~git20220903/phabricator/src/applications/releeph/view/branch/ReleephBranchPreviewView.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/view/branch/ReleephBranchPreviewView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/view/branch/ReleephBranchPreviewView.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -<?php - -final class ReleephBranchPreviewView extends AphrontFormControl { - - private $statics = array(); - private $dynamics = array(); - - public function addControl($param_name, AphrontFormControl $control) { - $celerity_id = celerity_generate_unique_node_id(); - $control->setID($celerity_id); - $this->dynamics[$param_name] = $celerity_id; - return $this; - } - - public function addStatic($param_name, $value) { - $this->statics[$param_name] = $value; - return $this; - } - - protected function getCustomControlClass() { - require_celerity_resource('releeph-preview-branch'); - return 'releeph-preview-branch'; - } - - protected function renderInput() { - static $required_params = array( - 'repositoryPHID', - 'projectName', - 'isSymbolic', - 'template', - ); - - $all_params = array_merge($this->statics, $this->dynamics); - foreach ($required_params as $param_name) { - if (idx($all_params, $param_name) === null) { - throw new Exception( - pht( - "'%s' is not set as either a static or dynamic!", - $param_name)); - } - } - - $output_id = celerity_generate_unique_node_id(); - - Javelin::initBehavior('releeph-preview-branch', array( - 'uri' => '/releeph/branch/preview/', - 'outputID' => $output_id, - 'params' => array( - 'static' => $this->statics, - 'dynamic' => $this->dynamics, - ), - )); - - return phutil_tag( - 'div', - array( - 'id' => $output_id, - ), - ''); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/view/branch/ReleephBranchTemplate.php phabricator-0~git20220903/phabricator/src/applications/releeph/view/branch/ReleephBranchTemplate.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/view/branch/ReleephBranchTemplate.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/view/branch/ReleephBranchTemplate.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -<?php - -final class ReleephBranchTemplate extends Phobject { - - const KEY = 'releeph.default-branch-template'; - - private $commitHandle; - private $branchDate = null; - private $projectName; - private $isSymbolic; - - public static function getDefaultTemplate() { - return PhabricatorEnv::getEnvConfig(self::KEY); - } - - public static function getRequiredDefaultTemplate() { - $template = self::getDefaultTemplate(); - if (!$template) { - throw new Exception(pht( - "Config setting '%s' must be set, ". - "or you must provide a branch-template for each project!", - self::KEY)); - } - return $template; - } - - public static function getFakeCommitHandleFor( - $repository_phid, - PhabricatorUser $viewer) { - - $repository = id(new PhabricatorRepositoryQuery()) - ->setViewer($viewer) - ->withPHIDs(array($repository_phid)) - ->executeOne(); - - $fake_handle = 'SOFAKE'; - if ($repository) { - $fake_handle = id(new PhabricatorObjectHandle()) - ->setName($repository->formatCommitName('100000000000')); - } - return $fake_handle; - } - - public function setCommitHandle(PhabricatorObjectHandle $handle) { - $this->commitHandle = $handle; - return $this; - } - - public function setBranchDate($branch_date) { - $this->branchDate = $branch_date; - return $this; - } - - public function setReleephProjectName($project_name) { - $this->projectName = $project_name; - return $this; - } - - public function setSymbolic($is_symbolic) { - $this->isSymbolic = $is_symbolic; - return $this; - } - - public function interpolate($template) { - if (!$this->projectName) { - return array('', array()); - } - - list($name, $name_errors) = $this->interpolateInner( - $template, - $this->isSymbolic); - - if ($this->isSymbolic) { - return array($name, $name_errors); - } else { - $validate_errors = $this->validateAsBranchName($name); - $errors = array_merge($name_errors, $validate_errors); - return array($name, $errors); - } - } - - /* - * xsprintf() would be useful here, but that's for formatting concrete lists - * of things in a certain way... - * - * animal_printf('%A %A %A', $dog1, $dog2, $dog3); - * - * ...rather than interpolating percent-control-strings like strftime does. - */ - private function interpolateInner($template, $is_symbolic) { - $name = $template; - $errors = array(); - - $safe_project_name = str_replace(' ', '-', $this->projectName); - $short_commit_id = last( - preg_split('/r[A-Z]+/', $this->commitHandle->getName())); - - $interpolations = array(); - for ($ii = 0; $ii < strlen($name); $ii++) { - $char = substr($name, $ii, 1); - $prev = null; - if ($ii > 0) { - $prev = substr($name, $ii - 1, 1); - } - $next = substr($name, $ii + 1, 1); - if ($next && $char == '%' && $prev != '%') { - $interpolations[$ii] = $next; - } - } - - $variable_interpolations = array(); - - $reverse_interpolations = $interpolations; - krsort($reverse_interpolations); - - if ($this->branchDate) { - $branch_date = $this->branchDate; - } else { - $branch_date = $this->commitHandle->getTimestamp(); - } - - foreach ($reverse_interpolations as $position => $code) { - $replacement = null; - switch ($code) { - case 'v': - $replacement = $this->commitHandle->getName(); - $is_variable = true; - break; - - case 'V': - $replacement = $short_commit_id; - $is_variable = true; - break; - - case 'P': - $replacement = $safe_project_name; - $is_variable = false; - break; - - case 'p': - $replacement = strtolower($safe_project_name); - $is_variable = false; - break; - - default: - // Format anything else using strftime() - $replacement = strftime("%{$code}", $branch_date); - $is_variable = true; - break; - } - - if ($is_variable) { - $variable_interpolations[] = $code; - } - $name = substr_replace($name, $replacement, $position, 2); - } - - if (!$is_symbolic && !$variable_interpolations) { - $errors[] = pht("Include additional interpolations that aren't static!"); - } - - return array($name, $errors); - } - - private function validateAsBranchName($name) { - $errors = array(); - - if (preg_match('{^/}', $name) || preg_match('{/$}', $name)) { - $errors[] = pht("Branches cannot begin or end with '%s'", '/'); - } - - if (preg_match('{//+}', $name)) { - $errors[] = pht("Branches cannot contain multiple consecutive '%s'", '/'); - } - - $parts = array_filter(explode('/', $name)); - foreach ($parts as $index => $part) { - $part_error = null; - if (preg_match('{^\.}', $part) || preg_match('{\.$}', $part)) { - $errors[] = pht("Path components cannot begin or end with '%s'", '.'); - } else if (preg_match('{^(?!\w)}', $part)) { - $errors[] = pht('Path components must begin with an alphanumeric.'); - } else if (!preg_match('{^\w ([\w-_%\.]* [\w-_%])?$}x', $part)) { - $errors[] = pht( - "Path components may only contain alphanumerics ". - "or '%s', '%s' or '%s'.", - '-', - '_', - '.'); - } - } - - return $errors; - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/view/ReleephRequestView.php phabricator-0~git20220903/phabricator/src/applications/releeph/view/ReleephRequestView.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/view/ReleephRequestView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/view/ReleephRequestView.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -<?php - -final class ReleephRequestView extends AphrontView { - - private $pullRequest; - private $customFields; - private $isListView; - - public function setIsListView($is_list_view) { - $this->isListView = $is_list_view; - return $this; - } - - public function getIsListView() { - return $this->isListView; - } - - public function setCustomFields(PhabricatorCustomFieldList $custom_fields) { - $this->customFields = $custom_fields; - return $this; - } - - public function getCustomFields() { - return $this->customFields; - } - - public function setPullRequest(ReleephRequest $pull_request) { - $this->pullRequest = $pull_request; - return $this; - } - - public function getPullRequest() { - return $this->pullRequest; - } - - public function render() { - $viewer = $this->getUser(); - - $field_list = $this->getCustomFields(); - $pull = $this->getPullRequest(); - - $header = $this->buildHeader($pull); - - $action_list = $this->buildActionList($pull); - - $property_list = id(new PHUIPropertyListView()) - ->setUser($viewer) - ->setActionList($action_list); - - $field_list->appendFieldsToPropertyList( - $pull, - $viewer, - $property_list); - - $warnings = $this->getWarnings($pull); - - if ($this->getIsListView()) { - Javelin::initBehavior('releeph-request-state-change'); - } - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setFormErrors($warnings) - ->addSigil('releeph-request-box') - ->setMetadata(array('uri' => '/'.$pull->getMonogram())) - ->appendChild($property_list); - } - - private function buildHeader(ReleephRequest $pull) { - $header_text = $pull->getSummaryForDisplay(); - if ($this->getIsListView()) { - $header_text = phutil_tag( - 'a', - array( - 'href' => '/'.$pull->getMonogram(), - ), - $header_text); - } - - $header = id(new PHUIHeaderView()) - ->setHeader($header_text) - ->setUser($this->getUser()) - ->setPolicyObject($pull); - - switch ($pull->getStatus()) { - case ReleephRequestStatus::STATUS_REQUESTED: - $icon = 'open'; - $color = null; - break; - case ReleephRequestStatus::STATUS_REJECTED: - $icon = 'reject'; - $color = 'red'; - break; - case ReleephRequestStatus::STATUS_PICKED: - $icon = 'accept'; - $color = 'green'; - break; - case ReleephRequestStatus::STATUS_REVERTED: - case ReleephRequestStatus::STATUS_ABANDONED: - $icon = 'reject'; - $color = 'dark'; - break; - case ReleephRequestStatus::STATUS_NEEDS_PICK: - $icon = 'warning'; - $color = 'green'; - break; - case ReleephRequestStatus::STATUS_NEEDS_REVERT: - $icon = 'warning'; - $color = 'red'; - break; - default: - $icon = 'question'; - $color = null; - break; - } - $text = ReleephRequestStatus::getStatusDescriptionFor($pull->getStatus()); - $header->setStatus($icon, $color, $text); - - return $header; - } - - private function buildActionList(ReleephRequest $pull) { - $viewer = $this->getUser(); - $id = $pull->getID(); - - $edit_uri = '/releeph/request/edit/'.$id.'/'; - - $view = id(new PhabricatorActionListView()) - ->setUser($viewer); - - $product = $pull->getBranch()->getProduct(); - $viewer_is_pusher = $product->isAuthoritativePHID($viewer->getPHID()); - $viewer_is_requestor = ($pull->getRequestUserPHID() == $viewer->getPHID()); - - if ($viewer_is_pusher) { - $yes_text = pht('Approve Pull'); - $no_text = pht('Reject Pull'); - $yes_icon = 'fa-check'; - $no_icon = 'fa-times'; - } else if ($viewer_is_requestor) { - $yes_text = pht('Request Pull'); - $no_text = pht('Cancel Pull'); - $yes_icon = 'fa-check'; - $no_icon = 'fa-times'; - } else { - $yes_text = pht('Support Pull'); - $no_text = pht('Discourage Pull'); - $yes_icon = 'fa-thumbs-o-up'; - $no_icon = 'fa-thumbs-o-down'; - } - - $yes_href = '/releeph/request/action/want/'.$id.'/'; - $no_href = '/releeph/request/action/pass/'.$id.'/'; - - $intents = $pull->getUserIntents(); - $current_intent = idx($intents, $viewer->getPHID()); - - $yes_disabled = ($current_intent == ReleephRequest::INTENT_WANT); - $no_disabled = ($current_intent == ReleephRequest::INTENT_PASS); - - $use_workflow = (!$this->getIsListView()); - - $view->addAction( - id(new PhabricatorActionView()) - ->setName($yes_text) - ->setHref($yes_href) - ->setWorkflow($use_workflow) - ->setRenderAsForm($use_workflow) - ->setDisabled($yes_disabled) - ->addSigil('releeph-request-state-change') - ->addSigil('want') - ->setIcon($yes_icon)); - - $view->addAction( - id(new PhabricatorActionView()) - ->setName($no_text) - ->setHref($no_href) - ->setWorkflow($use_workflow) - ->setRenderAsForm($use_workflow) - ->setDisabled($no_disabled) - ->addSigil('releeph-request-state-change') - ->addSigil('pass') - ->setIcon($no_icon)); - - - if ($viewer_is_pusher || $viewer_is_requestor) { - - $pulled_href = '/releeph/request/action/mark-manually-picked/'.$id.'/'; - $revert_href = '/releeph/request/action/mark-manually-reverted/'.$id.'/'; - - if ($pull->getInBranch()) { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Mark as Reverted')) - ->setHref($revert_href) - ->setWorkflow($use_workflow) - ->setRenderAsForm($use_workflow) - ->addSigil('releeph-request-state-change') - ->addSigil('mark-manually-reverted') - ->setIcon($no_icon)); - } else { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Mark as Pulled')) - ->setHref($pulled_href) - ->setWorkflow($use_workflow) - ->setRenderAsForm($use_workflow) - ->addSigil('releeph-request-state-change') - ->addSigil('mark-manually-picked') - ->setIcon('fa-exclamation-triangle')); - } - } - - - if (!$this->getIsListView()) { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Edit Pull Request')) - ->setIcon('fa-pencil') - ->setHref($edit_uri)); - } - - return $view; - } - - private function getWarnings(ReleephRequest $pull) { - $warnings = array(); - - switch ($pull->getStatus()) { - case ReleephRequestStatus::STATUS_NEEDS_PICK: - if ($pull->getPickStatus() == ReleephRequest::PICK_FAILED) { - $warnings[] = pht('Last pull failed!'); - } - break; - case ReleephRequestStatus::STATUS_NEEDS_REVERT: - if ($pull->getPickStatus() == ReleephRequest::REVERT_FAILED) { - $warnings[] = pht('Last revert failed!'); - } - break; - } - - return $warnings; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/releeph/view/request/ReleephRequestTypeaheadControl.php phabricator-0~git20220903/phabricator/src/applications/releeph/view/request/ReleephRequestTypeaheadControl.php --- phabricator-0~git20200925/phabricator/src/applications/releeph/view/request/ReleephRequestTypeaheadControl.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/releeph/view/request/ReleephRequestTypeaheadControl.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -<?php - -final class ReleephRequestTypeaheadControl extends AphrontFormControl { - - const PLACEHOLDER = 'Type a commit id or first line of commit message...'; - - private $repo; - private $startTime; - - public function setRepo(PhabricatorRepository $repo) { - $this->repo = $repo; - return $this; - } - - public function setStartTime($epoch) { - $this->startTime = $epoch; - return $this; - } - - protected function getCustomControlClass() { - return 'releeph-request-typeahead'; - } - - protected function renderInput() { - $id = celerity_generate_unique_node_id(); - - $div = phutil_tag( - 'div', - array( - 'style' => 'position: relative;', - 'id' => $id, - ), - phutil_tag( - 'input', - array( - 'autocomplete' => 'off', - 'type' => 'text', - 'name' => $this->getName(), - ), - '')); - - require_celerity_resource('releeph-request-typeahead-css'); - - Javelin::initBehavior('releeph-request-typeahead', array( - 'id' => $id, - 'src' => '/releeph/request/typeahead/', - 'placeholder' => self::PLACEHOLDER, - 'value' => $this->getValue(), - 'aux' => array( - 'repo' => $this->repo->getID(), - 'callsign' => $this->repo->getCallsign(), - 'since' => $this->startTime, - 'limit' => 16, - ), - )); - - return $div; - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,7 +11,7 @@ } public function getMethodDescription() { - return pht('Process text through remarkup in Phabricator context.'); + return pht('Process text through remarkup.'); } protected function defineReturnType() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/remarkup/RemarkupValue.php phabricator-0~git20220903/phabricator/src/applications/remarkup/RemarkupValue.php --- phabricator-0~git20200925/phabricator/src/applications/remarkup/RemarkupValue.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/remarkup/RemarkupValue.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,27 @@ +<?php + +final class RemarkupValue + extends Phobject { + + private $corpus; + private $metadata; + + public function setCorpus($corpus) { + $this->corpus = $corpus; + return $this; + } + + public function getCorpus() { + return $this->corpus; + } + + public function setMetadata(array $metadata) { + $this->metadata = $metadata; + return $this; + } + + public function getMetadata() { + return $this->metadata; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php phabricator-0~git20220903/phabricator/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php --- phabricator-0~git20200925/phabricator/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php 2022-06-14 16:29:55.000000000 +0000 @@ -28,9 +28,10 @@ ->setDescription( pht( 'The default location in which to store working copies and other '. - 'data about repositories. Phabricator will control and manage '. + 'data about repositories. %s will control and manage '. 'data here, so you should **not** choose an existing directory '. - 'full of data you care about.')), + 'full of data you care about.', + PlatformSymbols::getPlatformServerName())), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/daemon/PhabricatorGitGraphStream.php phabricator-0~git20220903/phabricator/src/applications/repository/daemon/PhabricatorGitGraphStream.php --- phabricator-0~git20200925/phabricator/src/applications/repository/daemon/PhabricatorGitGraphStream.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/daemon/PhabricatorGitGraphStream.php 2022-06-14 16:29:55.000000000 +0000 @@ -19,13 +19,13 @@ if ($start_commit !== null) { $future = $repository->getLocalCommandFuture( - 'log --format=%s %s --', - '%H%x01%P%x01%ct', - $start_commit); + 'log %s %s --', + '--format=%H%x01%P%x01%ct', + gitsprintf('%s', $start_commit)); } else { $future = $repository->getLocalCommandFuture( - 'log --format=%s --all --', - '%H%x01%P%x01%ct'); + 'log %s --all --', + '--format=%H%x01%P%x01%ct'); } $this->iterator = new LinesOfALargeExecFuture($future); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/daemon/PhabricatorMercurialGraphStream.php phabricator-0~git20220903/phabricator/src/applications/repository/daemon/PhabricatorMercurialGraphStream.php --- phabricator-0~git20200925/phabricator/src/applications/repository/daemon/PhabricatorMercurialGraphStream.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/daemon/PhabricatorMercurialGraphStream.php 2022-06-14 16:29:55.000000000 +0000 @@ -16,13 +16,23 @@ private $local = array(); private $localParents = array(); - public function __construct(PhabricatorRepository $repository, $commit) { + public function __construct(PhabricatorRepository $repository, + $start_commit = null) { + $this->repository = $repository; + $command = 'log --template %s --rev %s'; + $template = '{rev}\1{node}\1{date}\1{parents}\2'; + if ($start_commit !== null) { + $revset = hgsprintf('reverse(ancestors(%s))', $start_commit); + } else { + $revset = 'reverse(all())'; + } + $future = $repository->getLocalCommandFuture( - 'log --template %s --rev %s', - '{rev}\1{node}\1{date}\1{parents}\2', - hgsprintf('reverse(ancestors(%s))', $commit)); + $command, + $template, + $revset); $this->iterator = new LinesOfALargeExecFuture($future); $this->iterator->setDelimiter("\2"); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryCommitRef.php phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryCommitRef.php --- phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryCommitRef.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryCommitRef.php 2022-06-14 16:29:55.000000000 +0000 @@ -5,7 +5,7 @@ private $identifier; private $epoch; private $branch; - private $canCloseImmediately; + private $isPermanent; private $parents = array(); public function setIdentifier($identifier) { @@ -35,13 +35,13 @@ return $this->branch; } - public function setCanCloseImmediately($can_close_immediately) { - $this->canCloseImmediately = $can_close_immediately; + public function setIsPermanent($is_permanent) { + $this->isPermanent = $is_permanent; return $this; } - public function getCanCloseImmediately() { - return $this->canCloseImmediately; + public function getIsPermanent() { + return $this->isPermanent; } public function setParents(array $parents) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php --- phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -101,7 +101,7 @@ $repository, $ref->getIdentifier(), $ref->getEpoch(), - $ref->getCanCloseImmediately(), + $ref->getIsPermanent(), $ref->getParents(), $task_priority); @@ -142,61 +142,86 @@ return array(); } - $heads = $this->sortRefs($heads); - $head_commits = mpull($heads, 'getCommitIdentifier'); - $this->log( pht( 'Discovering commits in repository "%s".', $repository->getDisplayName())); - $this->fillCommitCache($head_commits); + $ref_lists = array(); - $refs = array(); - foreach ($heads as $ref) { - $name = $ref->getShortName(); - $commit = $ref->getCommitIdentifier(); + $head_groups = $this->getRefGroupsForDiscovery($heads); + foreach ($head_groups as $head_group) { - $this->log( - pht( - 'Examining "%s" (%s) at "%s".', - $name, - $ref->getRefType(), - $commit)); + $group_identifiers = mpull($head_group, 'getCommitIdentifier'); + $group_identifiers = array_fuse($group_identifiers); + $this->fillCommitCache($group_identifiers); + + foreach ($head_group as $ref) { + $name = $ref->getShortName(); + $commit = $ref->getCommitIdentifier(); + + $this->log( + pht( + 'Examining "%s" (%s) at "%s".', + $name, + $ref->getRefType(), + $commit)); - if (!$repository->shouldTrackRef($ref)) { - $this->log(pht('Skipping, ref is untracked.')); - continue; - } + if (!$repository->shouldTrackRef($ref)) { + $this->log(pht('Skipping, ref is untracked.')); + continue; + } - if ($this->isKnownCommit($commit)) { - $this->log(pht('Skipping, HEAD is known.')); - continue; - } + if ($this->isKnownCommit($commit)) { + $this->log(pht('Skipping, HEAD is known.')); + continue; + } - // In Git, it's possible to tag anything. We just skip tags that don't - // point to a commit. See T11301. - $fields = $ref->getRawFields(); - $ref_type = idx($fields, 'objecttype'); - $tag_type = idx($fields, '*objecttype'); - if ($ref_type != 'commit' && $tag_type != 'commit') { - $this->log(pht('Skipping, this is not a commit.')); - continue; - } + // In Git, it's possible to tag anything. We just skip tags that don't + // point to a commit. See T11301. + $fields = $ref->getRawFields(); + $ref_type = idx($fields, 'objecttype'); + $tag_type = idx($fields, '*objecttype'); + if ($ref_type != 'commit' && $tag_type != 'commit') { + $this->log(pht('Skipping, this is not a commit.')); + continue; + } - $this->log(pht('Looking for new commits.')); + $this->log(pht('Looking for new commits.')); - $head_refs = $this->discoverStreamAncestry( - new PhabricatorGitGraphStream($repository, $commit), - $commit, - $publisher->shouldPublishRef($ref)); + $head_refs = $this->discoverStreamAncestry( + new PhabricatorGitGraphStream($repository, $commit), + $commit, + $publisher->isPermanentRef($ref)); - $this->didDiscoverRefs($head_refs); + $this->didDiscoverRefs($head_refs); - $refs[] = $head_refs; + $ref_lists[] = $head_refs; + } } - return array_mergev($refs); + $refs = array_mergev($ref_lists); + + return $refs; + } + + /** + * @task git + */ + private function getRefGroupsForDiscovery(array $heads) { + $heads = $this->sortRefs($heads); + + // See T13593. We hold a commit cache with a fixed maximum size. Split the + // refs into chunks no larger than the cache size, so we don't overflow the + // cache when testing them. + + $array_iterator = new ArrayIterator($heads); + + $chunk_iterator = new PhutilChunkedIterator( + $array_iterator, + self::MAX_COMMIT_CACHE_SIZE); + + return $chunk_iterator; } @@ -250,7 +275,7 @@ $refs[$identifier] = id(new PhabricatorRepositoryCommitRef()) ->setIdentifier($identifier) ->setEpoch($epoch) - ->setCanCloseImmediately(true); + ->setIsPermanent(true); if ($upper_bound === null) { $upper_bound = $identifier; @@ -354,7 +379,7 @@ $branch_refs = $this->discoverStreamAncestry( new PhabricatorMercurialGraphStream($repository, $commit), $commit, - $close_immediately = true); + $is_permanent = true); $this->didDiscoverRefs($branch_refs); @@ -371,7 +396,7 @@ private function discoverStreamAncestry( PhabricatorRepositoryGraphStream $stream, $commit, - $close_immediately) { + $is_permanent) { $discover = array($commit); $graph = array(); @@ -424,7 +449,7 @@ $refs[] = id(new PhabricatorRepositoryCommitRef()) ->setIdentifier($commit) ->setEpoch($epoch) - ->setCanCloseImmediately($close_immediately) + ->setIsPermanent($is_permanent) ->setParents($stream->getParents($commit)); } @@ -459,13 +484,6 @@ return true; } - if ($this->repairMode) { - // In repair mode, rediscover the entire repository, ignoring the - // database state. We can hit the local cache above, but if we miss it - // stop the script from going to the database cache. - return false; - } - $this->fillCommitCache(array($identifier)); return isset($this->commitCache[$identifier]); @@ -476,6 +494,13 @@ return; } + if ($this->repairMode) { + // In repair mode, rediscover the entire repository, ignoring the + // database state. The engine still maintains a local cache (the + // "Working Set") but we just give up before looking in the database. + return; + } + $max_size = self::MAX_COMMIT_CACHE_SIZE; // If we're filling more identifiers than would fit in the cache, ignore @@ -507,9 +532,9 @@ } /** - * Sort branches so we process closeable branches first. This makes the - * whole import process a little cheaper, since we can close these commits - * the first time through rather than catching them in the refs step. + * Sort refs so we process permanent refs first. This makes the whole import + * process a little cheaper, since we can publish these commits the first + * time through rather than catching them in the refs step. * * @task internal * @@ -523,7 +548,7 @@ $head_refs = array(); $tail_refs = array(); foreach ($refs as $ref) { - if ($publisher->shouldPublishRef($ref)) { + if ($publisher->isPermanentRef($ref)) { $head_refs[] = $ref; } else { $tail_refs[] = $ref; @@ -538,7 +563,7 @@ PhabricatorRepository $repository, $commit_identifier, $epoch, - $close_immediately, + $is_permanent, array $parents, $task_priority) { @@ -570,8 +595,8 @@ $commit->setRepositoryID($repository->getID()); $commit->setCommitIdentifier($commit_identifier); $commit->setEpoch($epoch); - if ($close_immediately) { - $commit->setImportStatus(PhabricatorRepositoryCommit::IMPORTED_CLOSEABLE); + if ($is_permanent) { + $commit->setImportStatus(PhabricatorRepositoryCommit::IMPORTED_PERMANENT); } $data = new PhabricatorRepositoryCommitData(); @@ -655,7 +680,11 @@ $epoch, $task_priority) { - $this->insertTask($repository, $commit, $task_priority); + $this->queueCommitImportTask( + $repository, + $commit->getPHID(), + $task_priority, + $via = 'discovery'); // Update the repository summary table. queryfx( @@ -679,36 +708,6 @@ } } - private function insertTask( - PhabricatorRepository $repository, - PhabricatorRepositoryCommit $commit, - $task_priority, - $data = array()) { - - $vcs = $repository->getVersionControlSystem(); - switch ($vcs) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: - $class = 'PhabricatorRepositoryGitCommitMessageParserWorker'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - $class = 'PhabricatorRepositorySvnCommitMessageParserWorker'; - break; - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: - $class = 'PhabricatorRepositoryMercurialCommitMessageParserWorker'; - break; - default: - throw new Exception(pht("Unknown repository type '%s'!", $vcs)); - } - - $data['commitID'] = $commit->getID(); - - $options = array( - 'priority' => $task_priority, - ); - - PhabricatorWorker::scheduleTask($class, $data, $options); - } - private function isInitialImport(array $refs) { $commit_count = count($refs); @@ -781,8 +780,7 @@ } private function markUnreachableCommits(PhabricatorRepository $repository) { - // For now, this is only supported for Git. - if (!$repository->isGit()) { + if (!$repository->isGit() && !$repository->isHg()) { return; } @@ -800,7 +798,11 @@ } // We can share a single graph stream across all the checks we need to do. - $stream = new PhabricatorGitGraphStream($repository); + if ($repository->isGit()) { + $stream = new PhabricatorGitGraphStream($repository); + } else if ($repository->isHg()) { + $stream = new PhabricatorMercurialGraphStream($repository); + } foreach ($old_refs as $old_ref) { $identifier = $old_ref->getCommitIdentifier(); @@ -813,7 +815,7 @@ private function markUnreachableFrom( PhabricatorRepository $repository, - PhabricatorGitGraphStream $stream, + PhabricatorRepositoryGraphStream $stream, $identifier) { $unreachable = array(); @@ -926,71 +928,4 @@ $data['epoch']); } - private function getImportTaskPriority( - PhabricatorRepository $repository, - array $refs) { - - // If the repository is importing for the first time, we schedule tasks - // at IMPORT priority, which is very low. Making progress on importing a - // new repository for the first time is less important than any other - // daemon task. - - // If the repository has finished importing and we're just catching up - // on recent commits, we usually schedule discovery at COMMIT priority, - // which is slightly below the default priority. - - // Note that followup tasks and triggered tasks (like those generated by - // Herald or Harbormaster) will queue at DEFAULT priority, so that each - // commit tends to fully import before we start the next one. This tends - // to give imports fairly predictable progress. See T11677 for some - // discussion. - - if ($repository->isImporting()) { - $this->log( - pht( - 'Importing %s commit(s) at low priority ("PRIORITY_IMPORT") '. - 'because this repository is still importing.', - phutil_count($refs))); - - return PhabricatorWorker::PRIORITY_IMPORT; - } - - // See T13369. If we've discovered a lot of commits at once, import them - // at lower priority. - - // This is mostly aimed at reducing the impact that synchronizing thousands - // of commits from a remote upstream has on other repositories. The queue - // is "mostly FIFO", so queueing a thousand commit imports can stall other - // repositories. - - // In a perfect world we'd probably give repositories round-robin queue - // priority, but we don't currently have the primitives for this and there - // isn't a strong case for building them. - - // Use "a whole lot of commits showed up at once" as a heuristic for - // detecting "someone synchronized an upstream", and import them at a lower - // priority to more closely approximate fair scheduling. - - if (count($refs) >= PhabricatorRepository::LOWPRI_THRESHOLD) { - $this->log( - pht( - 'Importing %s commit(s) at low priority ("PRIORITY_IMPORT") '. - 'because many commits were discovered at once.', - phutil_count($refs))); - - return PhabricatorWorker::PRIORITY_IMPORT; - } - - // Otherwise, import at normal priority. - - if ($refs) { - $this->log( - pht( - 'Importing %s commit(s) at normal priority ("PRIORITY_COMMIT").', - phutil_count($refs))); - } - - return PhabricatorWorker::PRIORITY_COMMIT; - } - } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryEngine.php phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryEngine.php --- phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -83,4 +83,114 @@ return $this; } + final protected function queueCommitImportTask( + PhabricatorRepository $repository, + $commit_phid, + $task_priority, + $via) { + + $vcs = $repository->getVersionControlSystem(); + switch ($vcs) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $class = 'PhabricatorRepositoryGitCommitMessageParserWorker'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $class = 'PhabricatorRepositorySvnCommitMessageParserWorker'; + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $class = 'PhabricatorRepositoryMercurialCommitMessageParserWorker'; + break; + default: + throw new Exception( + pht( + 'Unknown repository type "%s"!', + $vcs)); + } + + $data = array( + 'commitPHID' => $commit_phid, + ); + + if ($via !== null) { + $data['via'] = $via; + } + + $options = array( + 'priority' => $task_priority, + 'objectPHID' => $commit_phid, + 'containerPHID' => $repository->getPHID(), + ); + + PhabricatorWorker::scheduleTask($class, $data, $options); + } + + final protected function getImportTaskPriority( + PhabricatorRepository $repository, + array $refs) { + assert_instances_of($refs, 'PhabricatorRepositoryCommitRef'); + + // If the repository is importing for the first time, we schedule tasks + // at IMPORT priority, which is very low. Making progress on importing a + // new repository for the first time is less important than any other + // daemon task. + + // If the repository has finished importing and we're just catching up + // on recent commits, we usually schedule discovery at COMMIT priority, + // which is slightly below the default priority. + + // Note that followup tasks and triggered tasks (like those generated by + // Herald or Harbormaster) will queue at DEFAULT priority, so that each + // commit tends to fully import before we start the next one. This tends + // to give imports fairly predictable progress. See T11677 for some + // discussion. + + if ($repository->isImporting()) { + $this->log( + pht( + 'Importing %s commit(s) at low priority ("PRIORITY_IMPORT") '. + 'because this repository is still importing.', + phutil_count($refs))); + + return PhabricatorWorker::PRIORITY_IMPORT; + } + + // See T13369. If we've discovered a lot of commits at once, import them + // at lower priority. + + // This is mostly aimed at reducing the impact that synchronizing thousands + // of commits from a remote upstream has on other repositories. The queue + // is "mostly FIFO", so queueing a thousand commit imports can stall other + // repositories. + + // In a perfect world we'd probably give repositories round-robin queue + // priority, but we don't currently have the primitives for this and there + // isn't a strong case for building them. + + // Use "a whole lot of commits showed up at once" as a heuristic for + // detecting "someone synchronized an upstream", and import them at a lower + // priority to more closely approximate fair scheduling. + + if (count($refs) >= PhabricatorRepository::LOWPRI_THRESHOLD) { + $this->log( + pht( + 'Importing %s commit(s) at low priority ("PRIORITY_IMPORT") '. + 'because many commits were discovered at once.', + phutil_count($refs))); + + return PhabricatorWorker::PRIORITY_IMPORT; + } + + // Otherwise, import at normal priority. + + if ($refs) { + $this->log( + pht( + 'Importing %s commit(s) at normal priority ("PRIORITY_COMMIT").', + phutil_count($refs))); + } + + return PhabricatorWorker::PRIORITY_COMMIT; + } + + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryMirrorEngine.php phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryMirrorEngine.php --- phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryMirrorEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryMirrorEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -16,7 +16,7 @@ if (PhabricatorEnv::getEnvConfig('phabricator.silent')) { $this->log( - pht('Phabricator is running in silent mode; declining to mirror.')); + pht('This software is running in silent mode; declining to mirror.')); return; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php --- phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -723,7 +723,6 @@ // This behavior has been reverted, but users who updated between Feb 1, // 2012 and Mar 1, 2012 will have the erroring version. Do a dumb test // against stdout to check for this possibility. - // See: https://github.com/phacility/phabricator/issues/101/ // NOTE: Mercurial has translated versions, which translate this error // string. In a translated version, the string will be something else, diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php --- phabricator-0~git20200925/phabricator/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,7 +9,7 @@ private $newPositions = array(); private $deadPositions = array(); - private $closeCommits = array(); + private $permanentCommits = array(); private $rebuild; public function setRebuild($rebuild) { @@ -24,7 +24,7 @@ public function updateRefs() { $this->newPositions = array(); $this->deadPositions = array(); - $this->closeCommits = array(); + $this->permanentCommits = array(); $repository = $this->getRepository(); $viewer = $this->getViewer(); @@ -96,11 +96,11 @@ $this->updateCursors($cursor_group, $refs, $type, $all_closing_heads); } - if ($this->closeCommits) { - $this->setCloseFlagOnCommits($this->closeCommits); + if ($this->permanentCommits) { + $this->setPermanentFlagOnCommits($this->permanentCommits); } - $save_cursors = $this->getCursorsForUpdate($all_cursors); + $save_cursors = $this->getCursorsForUpdate($repository, $all_cursors); if ($this->newPositions || $this->deadPositions || $save_cursors) { $repository->openTransaction(); @@ -121,17 +121,19 @@ } } - private function getCursorsForUpdate(array $cursors) { + private function getCursorsForUpdate( + PhabricatorRepository $repository, + array $cursors) { assert_instances_of($cursors, 'PhabricatorRepositoryRefCursor'); + $publisher = $repository->newPublisher(); + $results = array(); foreach ($cursors as $cursor) { - $ref_type = $cursor->getRefType(); - $ref_name = $cursor->getRefName(); - - $is_permanent = $this->isPermanentRef($ref_type, $ref_name); + $diffusion_ref = $cursor->newDiffusionRepositoryRef(); + $is_permanent = $publisher->isPermanentRef($diffusion_ref); if ($is_permanent == $cursor->getIsPermanent()) { continue; } @@ -217,9 +219,9 @@ return $this; } - private function markCloseCommits(array $identifiers) { + private function markPermanentCommits(array $identifiers) { foreach ($identifiers as $identifier) { - $this->closeCommits[$identifier] = $identifier; + $this->permanentCommits[$identifier] = $identifier; } return $this; } @@ -259,6 +261,7 @@ $ref_type, array $all_closing_heads) { $repository = $this->getRepository(); + $publisher = $repository->newPublisher(); // NOTE: Mercurial branches may have multiple branch heads; this logic // is complex primarily to account for that. @@ -341,7 +344,7 @@ $this->markPositionNew($new_position); } - if ($this->isPermanentRef($ref_type, $name)) { + if ($publisher->isPermanentRef(head($refs))) { // See T13284. If this cursor was already marked as permanent, we // only need to publish the newly created ref positions. However, if @@ -377,7 +380,7 @@ $identifier, $exclude); - $this->markCloseCommits($new_identifiers); + $this->markPermanentCommits($new_identifiers); } } } @@ -404,14 +407,6 @@ } } - private function isPermanentRef($ref_type, $ref_name) { - if ($ref_type !== PhabricatorRepositoryRefCursor::TYPE_BRANCH) { - return false; - } - - return $this->getRepository()->isBranchPermanentRef($ref_name); - } - /** * Find all ancestors of a new closing branch head which are not ancestors * of any old closing branch head. @@ -483,17 +478,17 @@ $ref_list = implode("\n", $ref_list)."\n"; $future = $this->getRepository()->getLocalCommandFuture( - 'log --format=%s --stdin', - '%H'); + 'log %s --stdin --', + '--format=%H'); list($stdout) = $future ->write($ref_list) ->resolvex(); } else { list($stdout) = $this->getRepository()->execxLocalCommand( - 'log --format=%s %s', - '%H', - $new_head); + 'log %s %s --', + '--format=%H', + gitsprintf('%s', $new_head)); } $stdout = trim($stdout); @@ -507,10 +502,10 @@ } /** - * Mark a list of commits as closeable, and queue workers for those commits + * Mark a list of commits as permanent, and queue workers for those commits * which don't already have the flag. */ - private function setCloseFlagOnCommits(array $identifiers) { + private function setPermanentFlagOnCommits(array $identifiers) { $repository = $this->getRepository(); $commit_table = new PhabricatorRepositoryCommit(); $conn = $commit_table->establishConnection('w'); @@ -552,7 +547,23 @@ } } - $closeable_flag = PhabricatorRepositoryCommit::IMPORTED_CLOSEABLE; + $commit_refs = array(); + foreach ($identifiers as $identifier) { + + // See T13591. This construction is a bit ad-hoc, but the priority + // function currently only cares about the number of refs we have + // discovered, so we'll get the right result even without filling + // these records out in detail. + + $commit_refs[] = id(new PhabricatorRepositoryCommitRef()) + ->setIdentifier($identifier); + } + + $task_priority = $this->getImportTaskPriority( + $repository, + $commit_refs); + + $permanent_flag = PhabricatorRepositoryCommit::IMPORTED_PERMANENT; $published_flag = PhabricatorRepositoryCommit::IMPORTED_PUBLISH; $all_commits = ipull($all_commits, null, 'commitIdentifier'); @@ -568,9 +579,9 @@ } $import_status = $row['importStatus']; - if (!($import_status & $closeable_flag)) { - // Set the "closeable" flag. - $import_status = ($import_status | $closeable_flag); + if (!($import_status & $permanent_flag)) { + // Set the "permanent" flag. + $import_status = ($import_status | $permanent_flag); // See T13580. Clear the "published" flag, so publishing executes // again. We may have previously performed a no-op "publish" on the @@ -584,17 +595,11 @@ $import_status, $row['id']); - $data = array( - 'commitID' => $row['id'], - ); - - PhabricatorWorker::scheduleTask( - $class, - $data, - array( - 'priority' => PhabricatorWorker::PRIORITY_COMMIT, - 'objectPHID' => $row['phid'], - )); + $this->queueCommitImportTask( + $repository, + $row['phid'], + $task_priority, + $via = 'ref'); } } @@ -606,13 +611,17 @@ $ref_type, $ref_name) { - $is_permanent = $this->isPermanentRef($ref_type, $ref_name); - $cursor = id(new PhabricatorRepositoryRefCursor()) ->setRepositoryPHID($repository->getPHID()) ->setRefType($ref_type) - ->setRefName($ref_name) - ->setIsPermanent((int)$is_permanent); + ->setRefName($ref_name); + + $publisher = $repository->newPublisher(); + + $diffusion_ref = $cursor->newDiffusionRepositoryRef(); + $is_permanent = $publisher->isPermanentRef($diffusion_ref); + + $cursor->setIsPermanent((int)$is_permanent); try { return $cursor->save(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php phabricator-0~git20220903/phabricator/src/applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,6 +4,8 @@ extends PhabricatorWorkingCopyTestCase { public function testSubversionCommitDiscovery() { + $this->requireBinaryForTest('svn'); + $refs = $this->discoverRefs('ST'); $this->assertEqual( array( diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -47,7 +47,7 @@ ->loadPathIDs(); if (empty($path_map[$path_name])) { throw new PhutilArgumentUsageException( - pht('Path "%s" is not known to Phabricator.', $path_name)); + pht('Path "%s" is not unknown.', $path_name)); } $path_id = $path_map[$path_name]; diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -61,7 +61,7 @@ array( AlmanacClusterRepositoryServiceType::SERVICETYPE, )) - ->needBindings(true) + ->needActiveBindings(true) ->executeOne(); if (!$service) { throw new PhutilArgumentUsageException( diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,21 +7,22 @@ $this ->setName('discover') ->setExamples('**discover** [__options__] __repository__ ...') - ->setSynopsis(pht('Discover __repository__.')) + ->setSynopsis(pht('Discover commits in __repository__.')) ->setArguments( array( array( - 'name' => 'verbose', - 'help' => pht('Show additional debugging information.'), + 'name' => 'verbose', + 'help' => pht('Show additional debugging information.'), ), array( - 'name' => 'repair', - 'help' => pht( - 'Repair a repository with gaps in commit history.'), + 'name' => 'repair', + 'help' => pht( + 'Discover all commits, even if they are ancestors of known '. + 'commits. This can repair gaps in repository history.'), ), array( - 'name' => 'repos', - 'wildcard' => true, + 'name' => 'repos', + 'wildcard' => true, ), )); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementLockWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementLockWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementLockWorkflow.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementLockWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,139 @@ +<?php + +final class PhabricatorRepositoryManagementLockWorkflow + extends PhabricatorRepositoryManagementWorkflow { + + protected function didConstruct() { + $this + ->setName('lock') + ->setExamples('**lock** [options] __repository__ ...') + ->setSynopsis( + pht( + 'Temporarily lock clustered repositories to perform maintenance.')) + ->setArguments( + array( + array( + 'name' => 'repositories', + 'wildcard' => true, + ), + )); + } + + public function execute(PhutilArgumentParser $args) { + $viewer = $this->getViewer(); + + $repositories = $this->loadRepositories($args, 'repositories'); + if (!$repositories) { + throw new PhutilArgumentUsageException( + pht('Specify one or more repositories to lock.')); + } + + foreach ($repositories as $repository) { + $display_name = $repository->getDisplayName(); + + if (!$repository->isHosted()) { + throw new PhutilArgumentUsageException( + pht( + 'Unable to lock repository "%s": only hosted repositories may be '. + 'locked.', + $display_name)); + } + + if (!$repository->supportsSynchronization()) { + throw new PhutilArgumentUsageException( + pht( + 'Unable to lock repository "%s": only repositories that support '. + 'clustering may be locked.', + $display_name)); + } + + if (!$repository->getAlmanacServicePHID()) { + throw new PhutilArgumentUsageException( + pht( + 'Unable to lock repository "%s": only clustered repositories '. + 'may be locked.', + $display_name)); + } + } + + $diffusion_phid = id(new PhabricatorDiffusionApplication()) + ->getPHID(); + + $locks = array(); + foreach ($repositories as $repository) { + $engine = id(new DiffusionRepositoryClusterEngine()) + ->setViewer($viewer) + ->setActingAsPHID($diffusion_phid) + ->setRepository($repository); + + $event = $engine->newMaintenanceEvent(); + + $logs = array(); + $logs[] = $engine->newMaintenanceLog(); + + $locks[] = array( + 'repository' => $repository, + 'engine' => $engine, + 'event' => $event, + 'logs' => $logs, + ); + } + + $display_list = new PhutilConsoleList(); + foreach ($repositories as $repository) { + $display_list->addItem( + pht( + '%s %s', + $repository->getMonogram(), + $repository->getName())); + } + + echo tsprintf( + "%s\n\n%B\n", + pht('These repositories will be locked:'), + $display_list->drawConsoleString()); + + echo tsprintf( + "%s\n", + pht( + 'While the lock is held: users will be unable to write to this '. + 'repository, and you may safely perform working copy maintenance '. + 'on this node in another terminal window.')); + + $query = pht('Lock repositories and begin maintenance?'); + if (!phutil_console_confirm($query)) { + throw new ArcanistUserAbortException(); + } + + foreach ($locks as $key => $lock) { + $engine = $lock['engine']; + $engine->synchronizeWorkingCopyBeforeWrite(); + } + + echo tsprintf( + "%s\n", + pht( + 'Repositories are now locked. You may begin maintenance in '. + 'another terminal window. Keep this process running until '. + 'you complete the maintenance, then confirm that you are ready to '. + 'release the locks.')); + + while (!phutil_console_confirm('Ready to release the locks?')) { + // Wait for the user to confirm that they're ready. + } + + foreach ($locks as $key => $lock) { + $lock['event']->saveWithLogs($lock['logs']); + + $engine = $lock['engine']; + $engine->synchronizeWorkingCopyAfterWrite(); + } + + echo tsprintf( + "%s\n", + pht('Done.')); + + return 0; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -48,11 +48,11 @@ } private function markReachable(PhabricatorRepository $repository) { - if (!$repository->isGit()) { + if (!$repository->isGit() && !$repository->isHg()) { throw new PhutilArgumentUsageException( pht( - 'Only Git repositories are supported, this repository ("%s") is '. - 'not a Git repository.', + 'Only Git and Mercurial repositories are supported, unable to '. + 'operate on this repository ("%s").', $repository->getDisplayName())); } @@ -65,7 +65,12 @@ $flag = PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE; - $graph = new PhabricatorGitGraphStream($repository); + if ($repository->isGit()) { + $graph = new PhabricatorGitGraphStream($repository); + } else if ($repository->isHg()) { + $graph = new PhabricatorMercurialGraphStream($repository); + } + foreach ($commits as $commit) { $identifier = $commit->getCommitIdentifier(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -15,6 +15,12 @@ 'help' => pht('Show additional debugging information.'), ), array( + 'name' => 'ignore-locality', + 'help' => pht( + 'Pull even if the repository should not be present on this '. + 'host according to repository cluster configuration.'), + ), + array( 'name' => 'repos', 'wildcard' => true, ), @@ -22,8 +28,9 @@ } public function execute(PhutilArgumentParser $args) { - $repos = $this->loadLocalRepositories($args, 'repos'); + $ignore_locality = (bool)$args->getArg('ignore-locality'); + $repos = $this->loadLocalRepositories($args, 'repos', $ignore_locality); if (!$repos) { throw new PhutilArgumentUsageException( pht('Specify one or more repositories to pull.')); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -247,8 +247,9 @@ // all the requested steps explicitly. $spec = array( - 'commitID' => $commit->getID(), + 'commitPHID' => $commit->getPHID(), 'only' => !$importing, + 'via' => 'reparse', ); foreach ($classes as $class) { @@ -258,6 +259,8 @@ $spec, array( 'priority' => PhabricatorWorker::PRIORITY_IMPORT, + 'objectPHID' => $commit->getPHID(), + 'containerPHID' => $repository->getPHID(), )); } catch (PhabricatorWorkerPermanentFailureException $ex) { // See T13315. We expect some reparse steps to occasionally raise diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementWorkflow.php phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/management/PhabricatorRepositoryManagementWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,13 +35,18 @@ protected function loadLocalRepositories( PhutilArgumentParser $args, - $param) { + $param, + $ignore_locality = false) { $repositories = $this->loadRepositories($args, $param); if (!$repositories) { return $repositories; } + if ($ignore_locality) { + return $repositories; + } + $device = AlmanacKeys::getLiveDevice(); $viewer = $this->getViewer(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorRepositoryGitLFSRef(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -66,10 +66,6 @@ return 'identity'; } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPublisher.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPublisher.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPublisher.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPublisher.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,6 +38,10 @@ return !$this->getCommitHoldReasons($commit); } + public function isPermanentRef(DiffusionRepositoryRef $ref) { + return !$this->getRefImpermanentReasons($ref); + } + /* -( Hold Reasons )------------------------------------------------------- */ public function getRepositoryHoldReasons() { @@ -59,18 +63,8 @@ $repository = $this->getRepository(); $reasons = $this->getRepositoryHoldReasons(); - if (!$ref->isBranch()) { - $reasons[] = self::HOLD_REF_NOT_BRANCH; - } else { - $branch_name = $ref->getShortName(); - - if (!$repository->shouldTrackBranch($branch_name)) { - $reasons[] = self::HOLD_UNTRACKED; - } - - if (!$repository->isBranchPermanentRef($branch_name)) { - $reasons[] = self::HOLD_NOT_PERMANENT_REF; - } + foreach ($this->getRefImpermanentReasons($ref) as $reason) { + $reasons[] = $reason; } return $reasons; @@ -86,6 +80,27 @@ } } + return $reasons; + } + + public function getRefImpermanentReasons(DiffusionRepositoryRef $ref) { + $repository = $this->getRepository(); + $reasons = array(); + + if (!$ref->isBranch()) { + $reasons[] = self::HOLD_REF_NOT_BRANCH; + } else { + $branch_name = $ref->getShortName(); + + if (!$repository->shouldTrackBranch($branch_name)) { + $reasons[] = self::HOLD_UNTRACKED; + } + + if (!$repository->isBranchPermanentRef($branch_name)) { + $reasons[] = self::HOLD_NOT_PERMANENT_REF; + } + } + return $reasons; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPullEventQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPullEventQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPullEventQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPullEventQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,10 +40,6 @@ return new PhabricatorRepositoryPullEvent(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $events) { // If a pull targets an invalid repository or fails before authenticating, // it may not have an associated repository. diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPushEventQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPushEventQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPushEventQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPushEventQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorRepositoryPushEvent(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $events) { $repository_phids = mpull($events, 'getRepositoryPHID'); $repositories = id(new PhabricatorRepositoryQuery()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -64,10 +64,6 @@ return new PhabricatorRepositoryPushLog(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $logs) { $event_phids = mpull($logs, 'getPushEventPHID'); $events = id(new PhabricatorObjectQuery()) diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -633,7 +633,7 @@ $this->uuids); } - if (strlen($this->datasourceQuery)) { + if (phutil_nonempty_string($this->datasourceQuery)) { // This handles having "rP" match callsigns starting with "P...". $query = trim($this->datasourceQuery); if (preg_match('/^r/', $query)) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryRefCursorQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -50,10 +50,6 @@ return new PhabricatorRepositoryRefCursor(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $refs) { $repository_phids = mpull($refs, 'getRepositoryPHID'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositorySyncEventQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositorySyncEventQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositorySyncEventQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositorySyncEventQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,10 +34,6 @@ return new PhabricatorRepositorySyncEvent(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $events) { $repository_phids = mpull($events, 'getRepositoryPHID'); $repository_phids = array_filter($repository_phids); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryURIQuery.php phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryURIQuery.php --- phabricator-0~git20200925/phabricator/src/applications/repository/query/PhabricatorRepositoryURIQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/query/PhabricatorRepositoryURIQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -34,10 +34,6 @@ return new PhabricatorRepositoryURI(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/response/PhabricatorVCSResponse.php phabricator-0~git20220903/phabricator/src/applications/repository/response/PhabricatorVCSResponse.php --- phabricator-0~git20200925/phabricator/src/applications/repository/response/PhabricatorVCSResponse.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/response/PhabricatorVCSResponse.php 2022-06-14 16:29:55.000000000 +0000 @@ -2,7 +2,9 @@ /** * In Git, there appears to be no way to send a message which will be output - * by `git clone http://...`, although the response code is visible. + * by `git clone http://...`, although the response code is visible. We send + * the message in a header which is visible with "GIT_CURL_VERBOSE" if you + * know where to look. * * In Mercurial, the HTTP status response message is printed to the console, so * we send human-readable text there. @@ -44,6 +46,16 @@ ); } + $message = $this->getMessage(); + if (strlen($message)) { + foreach (phutil_split_lines($message, false) as $line) { + $headers[] = array( + 'X-Phabricator-Message', + $line, + ); + } + } + return $headers; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php 2022-06-14 16:29:55.000000000 +0000 @@ -49,38 +49,14 @@ return $this->assertAttached($this->commit); } - public function isActiveAudit() { - switch ($this->getAuditStatus()) { - case PhabricatorAuditStatusConstants::NONE: - case PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED: - case PhabricatorAuditStatusConstants::RESIGNED: - case PhabricatorAuditStatusConstants::CLOSED: - case PhabricatorAuditStatusConstants::CC: - return false; - } - - return true; - } - - public function isInteresting() { - switch ($this->getAuditStatus()) { - case PhabricatorAuditStatusConstants::NONE: - case PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED: - return false; - } - - return true; - } - public function isResigned() { - switch ($this->getAuditStatus()) { - case PhabricatorAuditStatusConstants::RESIGNED: - return true; - } - - return false; + return $this->getAuditRequestStatusObject()->isResigned(); } + public function getAuditRequestStatusObject() { + $status = $this->getAuditStatus(); + return PhabricatorAuditRequestStatus::newForStatus($status); + } /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryCommit.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryCommit.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryCommit.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryCommit.php 2022-06-14 16:29:55.000000000 +0000 @@ -36,7 +36,7 @@ const IMPORTED_PUBLISH = 8; const IMPORTED_ALL = 11; - const IMPORTED_CLOSEABLE = 1024; + const IMPORTED_PERMANENT = 1024; const IMPORTED_UNREACHABLE = 2048; private $commitData = self::ATTACHABLE; @@ -312,14 +312,14 @@ foreach ($requests as $request) { switch ($request->getAuditStatus()) { - case PhabricatorAuditStatusConstants::AUDIT_REQUIRED: - case PhabricatorAuditStatusConstants::AUDIT_REQUESTED: + case PhabricatorAuditRequestStatus::AUDIT_REQUIRED: + case PhabricatorAuditRequestStatus::AUDIT_REQUESTED: $any_need = true; break; - case PhabricatorAuditStatusConstants::ACCEPTED: + case PhabricatorAuditRequestStatus::ACCEPTED: $any_accept = true; break; - case PhabricatorAuditStatusConstants::CONCERNED: + case PhabricatorAuditRequestStatus::CONCERNED: $any_concern = true; break; } @@ -467,7 +467,7 @@ } public function isPermanentCommit() { - return (bool)$this->isPartiallyImported(self::IMPORTED_CLOSEABLE); + return (bool)$this->isPartiallyImported(self::IMPORTED_PERMANENT); } public function newCommitAuthorView(PhabricatorUser $viewer) { @@ -528,6 +528,12 @@ return $data->getCommitterString(); } + public function getCommitMessageForDisplay() { + $data = $this->getCommitData(); + $message = $data->getCommitMessage(); + return $message; + } + public function newCommitRef(PhabricatorUser $viewer) { $repository = $this->getRepository(); @@ -668,9 +674,9 @@ return array( 'buildable.commit' => pht('The commit identifier, if applicable.'), 'repository.callsign' => - pht('The callsign of the repository in Phabricator.'), + pht('The callsign of the repository.'), 'repository.phid' => - pht('The PHID of the repository in Phabricator.'), + pht('The PHID of the repository.'), 'repository.vcs' => pht('The version control system, either "svn", "hg" or "git".'), 'repository.uri' => @@ -708,8 +714,8 @@ if (!$path) { throw new Exception( pht( - 'This commit ("%s") is associated with a repository ("%s") that '. - 'with a remote URI ("%s") that does not appear to be hosted on '. + 'This commit ("%s") is associated with a repository ("%s") which '. + 'has a remote URI ("%s") that does not appear to be hosted on '. 'GitHub. Repositories must be hosted on GitHub to be built with '. 'CircleCI.', $commit_phid, @@ -939,7 +945,10 @@ } public function getConduitSearchAttachments() { - return array(); + return array( + id(new DiffusionAuditorsSearchEngineAttachment()) + ->setAttachmentKey('auditors'), + ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepository.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepository.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepository.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepository.php 2022-06-14 16:29:55.000000000 +0000 @@ -193,7 +193,7 @@ public function getMonogram() { $callsign = $this->getCallsign(); - if (strlen($callsign)) { + if (phutil_nonempty_string($callsign)) { return "r{$callsign}"; } @@ -203,7 +203,8 @@ public function getDisplayName() { $slug = $this->getRepositorySlug(); - if (strlen($slug)) { + + if (phutil_nonempty_string($slug)) { return $slug; } @@ -281,9 +282,11 @@ public function getSubversionBaseURI($commit = null) { $subpath = $this->getDetail('svn-subpath'); - if (!strlen($subpath)) { + + if (!phutil_nonempty_string($subpath)) { $subpath = null; } + return $this->getSubversionPathURI($subpath, $commit); } @@ -301,7 +304,7 @@ $uri = rtrim($uri, '/'); - if (strlen($path)) { + if (phutil_nonempty_string($path)) { $path = rawurlencode($path); $path = str_replace('%2F', '/', $path); $uri = $uri.'/'.ltrim($path, '/'); @@ -499,7 +502,7 @@ public function passthruRemoteCommand($pattern /* , $arg, ... */) { $args = func_get_args(); - return $this->newRemoteCommandPassthru($args)->execute(); + return $this->newRemoteCommandPassthru($args)->resolve(); } private function newRemoteCommandFuture(array $argv) { @@ -540,7 +543,7 @@ public function passthruLocalCommand($pattern /* , $arg, ... */) { $args = func_get_args(); - return $this->newLocalCommandPassthru($args)->execute(); + return $this->newLocalCommandPassthru($args)->resolve(); } private function newLocalCommandFuture(array $argv) { @@ -574,12 +577,12 @@ public function getURI() { $short_name = $this->getRepositorySlug(); - if (strlen($short_name)) { + if (phutil_nonempty_string($short_name)) { return "/source/{$short_name}/"; } $callsign = $this->getCallsign(); - if (strlen($callsign)) { + if (phutil_nonempty_string($callsign)) { return "/diffusion/{$callsign}/"; } @@ -593,7 +596,7 @@ public function getCommitURI($identifier) { $callsign = $this->getCallsign(); - if (strlen($callsign)) { + if (phutil_nonempty_string($callsign)) { return "/r{$callsign}{$identifier}"; } @@ -736,25 +739,26 @@ return $this->getCommitURI($commit); } - if (strlen($path)) { + if (phutil_nonempty_string($path)) { $path = ltrim($path, '/'); $path = str_replace(array(';', '$'), array(';;', '$$'), $path); $path = phutil_escape_uri($path); } $raw_branch = $branch; - if (strlen($branch)) { + if (phutil_nonempty_string($branch)) { $branch = phutil_escape_uri_path_component($branch); $path = "{$branch}/{$path}"; } $raw_commit = $commit; - if (strlen($commit)) { + if (phutil_nonempty_scalar($commit)) { $commit = str_replace('$', '$$', $commit); $commit = ';'.phutil_escape_uri($commit); } - if (strlen($line)) { + $line = phutil_string_cast($line); + if (phutil_nonempty_string($line)) { $line = '$'.phutil_escape_uri($line); } @@ -862,7 +866,7 @@ public function getDefaultBranch() { $default = $this->getDetail('default-branch'); - if (strlen($default)) { + if (phutil_nonempty_string($default)) { return $default; } @@ -1151,7 +1155,7 @@ /** * Get a parsed object representation of the repository's remote URI.. * - * @return wild A @{class@libphutil:PhutilURI}. + * @return wild A @{class@arcanist:PhutilURI}. * @task uri */ public function getRemoteURIObject() { @@ -1943,7 +1947,7 @@ 'point at this host, or the "device.id" configuration file on '. 'this host may be incorrect.'. "\n\n". - 'Requests routed within the cluster by Phabricator are always '. + 'Requests routed within the cluster are always '. 'expected to be sent to a node which can serve the request. To '. 'prevent loops, this request will not be proxied again.'. "\n\n". @@ -1975,7 +1979,7 @@ if ($writable) { foreach ($refs as $key => $ref) { if (!$ref->isWritable()) { - unset($results[$key]); + unset($refs[$key]); } } @@ -2109,7 +2113,7 @@ throw new Exception( pht( 'The Almanac service for this repository is not bound to any '. - 'interfaces.')); + 'active interfaces.')); } $uris = array(); @@ -2205,7 +2209,7 @@ throw new PhutilAggregateException( pht( 'Unable to read device public key while attempting to make '. - 'authenticated method call within the Phabricator cluster. '. + 'authenticated method call within the cluster. '. 'Use `%s` to register keys for this device. Exception: %s', 'bin/almanac register', $ex->getMessage()), @@ -2220,7 +2224,7 @@ throw new PhutilAggregateException( pht( 'Unable to read device private key while attempting to make '. - 'authenticated method call within the Phabricator cluster. '. + 'authenticated method call within the cluster. '. 'Use `%s` to register keys for this device. Exception: %s', 'bin/almanac register', $ex->getMessage()), @@ -2269,10 +2273,9 @@ $never_proxy); if (!$client) { - $result = id(new ConduitCall($method, $params)) - ->setUser($viewer) - ->execute(); - $future = new ImmediateFuture($result); + $conduit_call = id(new ConduitCall($method, $params)) + ->setUser($viewer); + $future = new MethodCallFuture($conduit_call, 'execute'); } else { $future = $client->callMethod($method, $params); } @@ -2531,7 +2534,7 @@ $service = id(new AlmanacServiceQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(array($service_phid)) - ->needBindings(true) + ->needActiveBindings(true) ->needProperties(true) ->executeOne(); if (!$service) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php 2022-06-14 16:29:55.000000000 +0000 @@ -81,6 +81,21 @@ return $this->assertAttached($this->logs); } + public function saveWithLogs(array $logs) { + assert_instances_of($logs, 'PhabricatorRepositoryPushLog'); + + $this->openTransaction(); + $this->save(); + foreach ($logs as $log) { + $log->setPushEventPHID($this->getPHID()); + $log->save(); + } + $this->saveTransaction(); + + $this->attachLogs($logs); + + return $this; + } /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushLog.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushLog.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushLog.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryPushLog.php 2022-06-14 16:29:55.000000000 +0000 @@ -18,6 +18,7 @@ const REFTYPE_BOOKMARK = 'bookmark'; const REFTYPE_COMMIT = 'commit'; const REFTYPE_REF = 'ref'; + const REFTYPE_MAINTENANCE = 'maintenance'; const CHANGEFLAG_ADD = 1; const CHANGEFLAG_DELETE = 2; @@ -27,6 +28,7 @@ const CHANGEFLAG_ENORMOUS = 32; const CHANGEFLAG_OVERSIZED = 64; const CHANGEFLAG_TOUCHES = 128; + const CHANGEFLAG_MAINTENANCE = 256; const REJECT_ACCEPT = 0; const REJECT_DANGEROUS = 1; @@ -70,6 +72,7 @@ self::CHANGEFLAG_ENORMOUS => pht('Enormous'), self::CHANGEFLAG_OVERSIZED => pht('Oversized'), self::CHANGEFLAG_TOUCHES => pht('Touches Too Many Paths'), + self::CHANGEFLAG_MAINTENANCE => pht('Maintenance'), ); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryRefCursor.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryRefCursor.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryRefCursor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryRefCursor.php 2022-06-14 16:29:55.000000000 +0000 @@ -88,6 +88,12 @@ return mpull($this->getPositions(), 'getCommitIdentifier'); } + public function newDiffusionRepositoryRef() { + return id(new DiffusionRepositoryRef()) + ->setRefType($this->getRefType()) + ->setShortName($this->getRefName()); + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryURI.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryURI.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/PhabricatorRepositoryURI.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/PhabricatorRepositoryURI.php 2022-06-14 16:29:55.000000000 +0000 @@ -501,7 +501,7 @@ 'color' => 'green', 'label' => pht('Observe'), 'note' => pht( - 'Phabricator will observe changes to this URI and copy them.'), + 'Changes to this URI will be observed and pulled.'), 'short' => pht('Copy from a remote.'), ), self::IO_MIRROR => array( @@ -509,7 +509,7 @@ 'color' => 'green', 'label' => pht('Mirror'), 'note' => pht( - 'Phabricator will push a copy of any changes to this URI.'), + 'A copy of any changes will be pushed to this URI.'), 'short' => pht('Push a copy to a remote.'), ), self::IO_NONE => array( @@ -517,7 +517,7 @@ 'color' => 'grey', 'label' => pht('No I/O'), 'note' => pht( - 'Phabricator will not push or pull any changes to this URI.'), + 'No changes will be pushed or pulled from this URI.'), 'short' => pht('Do not perform any I/O.'), ), self::IO_READ => array( @@ -525,8 +525,7 @@ 'color' => 'blue', 'label' => pht('Read Only'), 'note' => pht( - 'Phabricator will serve a read-only copy of the repository from '. - 'this URI.'), + 'A read-only copy of the repository will be served from this URI.'), 'short' => pht('Serve repository in read-only mode.'), ), self::IO_READWRITE => array( @@ -534,8 +533,7 @@ 'color' => 'blue', 'label' => pht('Read/Write'), 'note' => pht( - 'Phabricator will serve a read/write copy of the repository from '. - 'this URI.'), + 'A read/write copy of the repository will be served from this URI.'), 'short' => pht('Serve repository in read/write mode.'), ), ); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php phabricator-0~git20220903/phabricator/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -100,55 +100,6 @@ } - public function testFilterMercurialDebugOutput() { - $map = array( - '' => '', - - "quack\n" => "quack\n", - - "ignoring untrusted configuration option x.y = z\nquack\n" => - "quack\n", - - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "quack\n" => - "quack\n", - - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "quack\n" => - "quack\n", - - "quack\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n" => - "quack\n", - - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "duck\n". - "ignoring untrusted configuration option x.y = z\n". - "ignoring untrusted configuration option x.y = z\n". - "bread\n". - "ignoring untrusted configuration option x.y = z\n". - "quack\n" => - "duck\nbread\nquack\n", - - "ignoring untrusted configuration option x.y = z\n". - "duckignoring untrusted configuration option x.y = z\n". - "quack" => - 'duckquack', - ); - - foreach ($map as $input => $expect) { - $actual = DiffusionMercurialCommandEngine::filterMercurialDebugOutput( - $input); - $this->assertEqual($expect, $actual, $input); - } - } - public function testRepositoryShortNameValidation() { $good = array( 'sensible-repository', diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php phabricator-0~git20220903/phabricator/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php --- phabricator-0~git20200925/phabricator/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -99,14 +99,7 @@ } protected function finishParse() { - $commit = $this->commit; - if ($this->shouldQueueFollowupTasks()) { - $this->queueTask( - 'PhabricatorRepositoryCommitPublishWorker', - array( - 'commitID' => $commit->getID(), - )); - } + $this->queueCommitTask('PhabricatorRepositoryCommitPublishWorker'); } private function writeCommitChanges( diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php phabricator-0~git20220903/phabricator/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php --- phabricator-0~git20200925/phabricator/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -24,21 +24,7 @@ $this->updateCommitData($commit, $data); } - if ($this->shouldQueueFollowupTasks()) { - $this->queueTask( - $this->getFollowupTaskClass(), - array( - 'commitID' => $commit->getID(), - ), - array( - // We queue followup tasks at default priority so that the queue - // finishes work it has started before starting more work. If - // followups are queued at the same priority level, we do all - // message parses first, then all change parses, etc. This makes - // progress uneven. See T11677 for discussion. - 'priority' => PhabricatorWorker::PRIORITY_DEFAULT, - )); - } + $this->queueCommitTask($this->getFollowupTaskClass()); } final protected function updateCommitData( diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php phabricator-0~git20220903/phabricator/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php --- phabricator-0~git20200925/phabricator/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,30 +11,51 @@ return $this->commit; } - $commit_id = idx($this->getTaskData(), 'commitID'); - if (!$commit_id) { + $viewer = $this->getViewer(); + $task_data = $this->getTaskData(); + + $commit_query = id(new DiffusionCommitQuery()) + ->setViewer($viewer); + + $commit_phid = idx($task_data, 'commitPHID'); + + // TODO: See T13591. This supports execution of legacy tasks and can + // eventually be removed. Newer tasks use "commitPHID" instead of + // "commitID". + if (!$commit_phid) { + $commit_id = idx($task_data, 'commitID'); + if ($commit_id) { + $legacy_commit = id(clone $commit_query) + ->withIDs(array($commit_id)) + ->executeOne(); + if ($legacy_commit) { + $commit_phid = $legacy_commit->getPHID(); + } + } + } + + if (!$commit_phid) { throw new PhabricatorWorkerPermanentFailureException( - pht('No "%s" in task data.', 'commitID')); + pht('Task data has no "commitPHID".')); } - $commit = id(new DiffusionCommitQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withIDs(array($commit_id)) + $commit = id(clone $commit_query) + ->withPHIDs(array($commit_phid)) ->executeOne(); if (!$commit) { throw new PhabricatorWorkerPermanentFailureException( - pht('Commit "%s" does not exist.', $commit_id)); + pht('Commit "%s" does not exist.', $commit_phid)); } if ($commit->isUnreachable()) { throw new PhabricatorWorkerPermanentFailureException( pht( - 'Commit "%s" (with internal ID "%s") is no longer reachable from '. - 'any branch, tag, or ref in this repository, so it will not be '. + 'Commit "%s" (with PHID "%s") is no longer reachable from any '. + 'branch, tag, or ref in this repository, so it will not be '. 'imported. This usually means that the branch the commit was on '. 'was deleted or overwritten.', $commit->getMonogram(), - $commit_id)); + $commit_phid)); } $this->commit = $commit; @@ -51,10 +72,42 @@ $this->parseCommit($repository, $this->commit); } - final protected function shouldQueueFollowupTasks() { + private function shouldQueueFollowupTasks() { return !idx($this->getTaskData(), 'only'); } + final protected function queueCommitTask($task_class) { + if (!$this->shouldQueueFollowupTasks()) { + return; + } + + $commit = $this->loadCommit(); + $repository = $commit->getRepository(); + + $data = array( + 'commitPHID' => $commit->getPHID(), + ); + + $task_data = $this->getTaskData(); + if (isset($task_data['via'])) { + $data['via'] = $task_data['via']; + } + + $options = array( + // We queue followup tasks at default priority so that the queue finishes + // work it has started before starting more work. If followups are queued + // at the same priority level, we do all message parses first, then all + // change parses, etc. This makes progress uneven. See T11677 for + // discussion. + 'priority' => parent::PRIORITY_DEFAULT, + + 'objectPHID' => $commit->getPHID(), + 'containerPHID' => $repository->getPHID(), + ); + + $this->queueTask($task_class, $data, $options); + } + protected function getImportStepFlag() { return null; } @@ -112,7 +165,7 @@ $commit = id(new DiffusionCommitQuery()) ->setViewer($viewer) - ->withIDs(array(idx($this->getTaskData(), 'commitID'))) + ->withPHIDs(array(idx($this->getTaskData(), 'commitPHID'))) ->executeOne(); if (!$commit) { return $suffix; diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php phabricator-0~git20220903/phabricator/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -396,6 +396,8 @@ } public function testSubversionParser() { + $this->requireBinaryForTest('svn'); + $repository = $this->buildDiscoveredRepository('CHC'); $viewer = PhabricatorUser::getOmnipotentUser(); @@ -955,6 +957,8 @@ } public function testSubversionPartialParser() { + $this->requireBinaryForTest('svn'); + $repository = $this->buildBareRepository('CHD'); $repository->setDetail('svn-subpath', 'trunk/'); @@ -1059,6 +1063,8 @@ } public function testSubversionValidRootParser() { + $this->requireBinaryForTest('svn'); + // First, automatically configure the root correctly. $repository = $this->buildBareRepository('CHD'); id(new PhabricatorRepositoryPullEngine()) @@ -1104,6 +1110,8 @@ } public function testSubversionForeignStubsParser() { + $this->requireBinaryForTest('svn'); + $repository = $this->buildBareRepository('CHE'); $repository->setDetail('svn-subpath', 'branch/'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/repository/xaction/PhabricatorRepositoryVCSTransaction.php phabricator-0~git20220903/phabricator/src/applications/repository/xaction/PhabricatorRepositoryVCSTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/repository/xaction/PhabricatorRepositoryVCSTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/repository/xaction/PhabricatorRepositoryVCSTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -48,7 +48,7 @@ $errors[] = $this->newInvalidError( pht( 'Specified version control system must be a VCS '. - 'recognized by Phabricator. Valid systems are: %s.', + 'recognized by this software. Valid systems are: %s.', implode(', ', array_keys($vcs_map))), $xaction); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/compiler/PhutilSearchQueryCompiler.php phabricator-0~git20220903/phabricator/src/applications/search/compiler/PhutilSearchQueryCompiler.php --- phabricator-0~git20200925/phabricator/src/applications/search/compiler/PhutilSearchQueryCompiler.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/compiler/PhutilSearchQueryCompiler.php 2022-06-14 16:29:55.000000000 +0000 @@ -284,11 +284,24 @@ $operator = self::OPERATOR_AND; break; case '': - // See T12995. If this query term contains Chinese, Japanese or - // Korean characters, treat the term as a substring term by default. - // These languages do not separate words with spaces, so the term - // search mode is normally useless. - if ($enable_functions && !$is_quoted && phutil_utf8_is_cjk($value)) { + $use_substring = false; + + if ($enable_functions && !$is_quoted) { + // See T12995. If this query term contains Chinese, Japanese or + // Korean characters, treat the term as a substring term by default. + // These languages do not separate words with spaces, so the term + // search mode is normally useless. + if (phutil_utf8_is_cjk($value)) { + $use_substring = true; + } else if (phutil_preg_match('/^_/', $value)) { + // See T13632. Assume users searching for any term that begins + // with an undescore intend to perform substring search if they + // don't provide an explicit search function. + $use_substring = true; + } + } + + if ($use_substring) { $operator = self::OPERATOR_SUBSTRING; } else { $operator = self::OPERATOR_AND; diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php phabricator-0~git20220903/phabricator/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php --- phabricator-0~git20200925/phabricator/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -205,6 +205,20 @@ 'xyz', ), ), + + // See T12995. Interpret CJK tokens as substring queries since these + // languages do not use spaces as word separators. + "\xE7\x8C\xAB" => array( + array(null, $op_sub, "\xE7\x8C\xAB"), + ), + + // See T13632. Interpret tokens that begin with "_" as substring tokens + // if no function is specified. + '_x _y_ "_z_"' => array( + array(null, $op_sub, '_x'), + array(null, $op_sub, '_y_'), + array(null, $op_and, '_z_'), + ), ); $this->assertCompileFunctionQueries($function_tests); diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/controller/PhabricatorSearchDeleteController.php phabricator-0~git20220903/phabricator/src/applications/search/controller/PhabricatorSearchDeleteController.php --- phabricator-0~git20200925/phabricator/src/applications/search/controller/PhabricatorSearchDeleteController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/controller/PhabricatorSearchDeleteController.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,6 +42,19 @@ } $named_query = $engine->getBuiltinQuery($key); + + // After loading a global query, make sure the viewer actually has + // permission to view and edit it. + + PhabricatorPolicyFilter::requireCapability( + $viewer, + $named_query, + PhabricatorPolicyCapability::CAN_VIEW); + + PhabricatorPolicyFilter::requireCapability( + $viewer, + $named_query, + PhabricatorPolicyCapability::CAN_EDIT); } $builtin = null; diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/controller/PhabricatorSearchHovercardController.php phabricator-0~git20220903/phabricator/src/applications/search/controller/PhabricatorSearchHovercardController.php --- phabricator-0~git20200925/phabricator/src/applications/search/controller/PhabricatorSearchHovercardController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/controller/PhabricatorSearchHovercardController.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,7 +9,8 @@ public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); - $phids = $request->getArr('phids'); + + $cards = $request->getJSONMap('cards'); // If object names are provided, look them up and pretend they were // passed as additional PHIDs. This is primarily useful for debugging, @@ -23,26 +24,54 @@ ->execute(); foreach ($named_objects as $object) { - $phids[] = $object->getPHID(); + $cards[] = array( + 'objectPHID' => $object->getPHID(), + ); + } + } + + $object_phids = array(); + $handle_phids = array(); + $context_phids = array(); + foreach ($cards as $card) { + $object_phid = idx($card, 'objectPHID'); + + $handle_phids[] = $object_phid; + $object_phids[] = $object_phid; + + $context_phid = idx($card, 'contextPHID'); + + if ($context_phid) { + $object_phids[] = $context_phid; + $context_phids[] = $context_phid; } } $handles = id(new PhabricatorHandleQuery()) ->setViewer($viewer) - ->withPHIDs($phids) + ->withPHIDs($handle_phids) ->execute(); $objects = id(new PhabricatorObjectQuery()) ->setViewer($viewer) - ->withPHIDs($phids) + ->withPHIDs($object_phids) ->execute(); $objects = mpull($objects, null, 'getPHID'); + $context_objects = array_select_keys($objects, $context_phids); + + if ($context_objects) { + PhabricatorPolicyFilterSet::loadHandleViewCapabilities( + $viewer, + $handles, + $context_objects); + } + $extensions = PhabricatorHovercardEngineExtension::getAllEnabledExtensions(); $extension_maps = array(); - foreach ($extensions as $key => $extension) { + foreach ($extensions as $extension_key => $extension) { $extension->setViewer($viewer); $extension_phids = array(); @@ -52,56 +81,73 @@ } } - $extension_maps[$key] = $extension_phids; + $extension_maps[$extension_key] = $extension_phids; } $extension_data = array(); - foreach ($extensions as $key => $extension) { - $extension_phids = $extension_maps[$key]; + foreach ($extensions as $extension_key => $extension) { + $extension_phids = $extension_maps[$extension_key]; if (!$extension_phids) { - unset($extensions[$key]); + unset($extensions[$extension_key]); continue; } - $extension_data[$key] = $extension->willRenderHovercards( + $extension_data[$extension_key] = $extension->willRenderHovercards( array_select_keys($objects, $extension_phids)); } - $cards = array(); - foreach ($phids as $phid) { - $handle = $handles[$phid]; - $object = idx($objects, $phid); + $results = array(); + foreach ($cards as $card_key => $card) { + $object_phid = $card['objectPHID']; + + $handle = $handles[$object_phid]; + $object = idx($objects, $object_phid); + + $context_phid = idx($card, 'contextPHID'); + if ($context_phid) { + $context_object = idx($context_objects, $context_phid); + } else { + $context_object = null; + } $hovercard = id(new PHUIHovercardView()) ->setUser($viewer) ->setObjectHandle($handle); + if ($context_object) { + if ($handle->hasCapabilities()) { + if (!$handle->hasViewCapability($context_object)) { + $hovercard->setIsExiled(true); + } + } + } + if ($object) { $hovercard->setObject($object); - foreach ($extension_maps as $key => $extension_phids) { - if (isset($extension_phids[$phid])) { - $extensions[$key]->renderHovercard( + foreach ($extension_maps as $extension_key => $extension_phids) { + if (isset($extension_phids[$object_phid])) { + $extensions[$extension_key]->renderHovercard( $hovercard, $handle, $object, - $extension_data[$key]); + $extension_data[$extension_key]); } } } - $cards[$phid] = $hovercard; + $results[$card_key] = $hovercard; } if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent( array( - 'cards' => $cards, + 'cards' => $results, )); } - foreach ($cards as $key => $hovercard) { - $cards[$key] = phutil_tag('div', + foreach ($results as $result_key => $hovercard) { + $results[$result_key] = phutil_tag('div', array( 'class' => 'ml', ), @@ -109,7 +155,7 @@ } return $this->newPage() - ->appendChild($cards) + ->appendChild($results) ->setShowFooter(false); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -60,7 +60,7 @@ PhabricatorEnv::getDoclink('Conduit API: Using Search Endpoints')); } - final public function getMethodDocumentation() { + final protected function newDocumentationPages(PhabricatorUser $viewer) { $viewer = $this->getViewer(); $engine = $this->newSearchEngine() @@ -70,17 +70,18 @@ $out = array(); - $out[] = $this->buildQueriesBox($engine); - $out[] = $this->buildConstraintsBox($engine); - $out[] = $this->buildOrderBox($engine, $query); - $out[] = $this->buildFieldsBox($engine); - $out[] = $this->buildAttachmentsBox($engine); - $out[] = $this->buildPagingBox($engine); + $out[] = $this->buildQueriesDocumentationPage($viewer, $engine); + $out[] = $this->buildConstraintsDocumentationPage($viewer, $engine); + $out[] = $this->buildOrderDocumentationPage($viewer, $engine, $query); + $out[] = $this->buildFieldsDocumentationPage($viewer, $engine); + $out[] = $this->buildAttachmentsDocumentationPage($viewer, $engine); + $out[] = $this->buildPagingDocumentationPage($viewer, $engine); return $out; } - private function buildQueriesBox( + private function buildQueriesDocumentationPage( + PhabricatorUser $viewer, PhabricatorApplicationSearchEngine $engine) { $viewer = $this->getViewer(); @@ -140,15 +141,18 @@ null, )); - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Builtin and Saved Queries')) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->newRemarkupDocumentationView($info)) - ->appendChild($table); + $title = pht('Prebuilt Queries'); + $content = array( + $this->newRemarkupDocumentationView($info), + $table, + ); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('queries'); } - private function buildConstraintsBox( + private function buildConstraintsDocumentationPage( + PhabricatorUser $viewer, PhabricatorApplicationSearchEngine $engine) { $info = pht(<<<EOTEXT @@ -169,8 +173,8 @@ { ... "constraints": { - "authors": ["PHID-USER-1111", "PHID-USER-2222"], - "statuses": ["open", "closed"], + "authorPHIDs": ["PHID-USER-1111", "PHID-USER-2222"], + "flavors": ["cherry", "orange"], ... }, ... @@ -281,16 +285,21 @@ 'wide', )); - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Custom Query Constraints')) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->newRemarkupDocumentationView($info)) - ->appendChild($table) - ->appendChild($constant_lists); + + $title = pht('Constraints'); + $content = array( + $this->newRemarkupDocumentationView($info), + $table, + $constant_lists, + ); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('constraints') + ->setIconIcon('fa-filter'); } - private function buildOrderBox( + private function buildOrderDocumentationPage( + PhabricatorUser $viewer, PhabricatorApplicationSearchEngine $engine, $query) { @@ -388,18 +397,21 @@ 'wide', )); - - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Result Ordering')) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->newRemarkupDocumentationView($orders_info)) - ->appendChild($orders_table) - ->appendChild($this->newRemarkupDocumentationView($columns_info)) - ->appendChild($columns_table); + $title = pht('Result Ordering'); + $content = array( + $this->newRemarkupDocumentationView($orders_info), + $orders_table, + $this->newRemarkupDocumentationView($columns_info), + $columns_table, + ); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('ordering') + ->setIconIcon('fa-sort-numeric-asc'); } - private function buildFieldsBox( + private function buildFieldsDocumentationPage( + PhabricatorUser $viewer, PhabricatorApplicationSearchEngine $engine) { $info = pht(<<<EOTEXT @@ -470,15 +482,19 @@ 'wide', )); - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Object Fields')) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->newRemarkupDocumentationView($info)) - ->appendChild($table); + $title = pht('Object Fields'); + $content = array( + $this->newRemarkupDocumentationView($info), + $table, + ); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('fields') + ->setIconIcon('fa-cube'); } - private function buildAttachmentsBox( + private function buildAttachmentsDocumentationPage( + PhabricatorUser $viewer, PhabricatorApplicationSearchEngine $engine) { $info = pht(<<<EOTEXT @@ -560,15 +576,19 @@ 'wide', )); - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Attachments')) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->newRemarkupDocumentationView($info)) - ->appendChild($table); + $title = pht('Attachments'); + $content = array( + $this->newRemarkupDocumentationView($info), + $table, + ); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('attachments') + ->setIconIcon('fa-cubes'); } - private function buildPagingBox( + private function buildPagingDocumentationPage( + PhabricatorUser $viewer, PhabricatorApplicationSearchEngine $engine) { $info = pht(<<<EOTEXT @@ -631,11 +651,14 @@ EOTEXT ); - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Paging and Limits')) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->newRemarkupDocumentationView($info)); + $title = pht('Paging and Limits'); + $content = array( + $this->newRemarkupDocumentationView($info), + ); + + return $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('paging') + ->setIconIcon('fa-clone'); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/engineextension/PhabricatorFerretFulltextEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -134,123 +134,297 @@ $ngram_engine = new PhabricatorSearchNgramEngine(); $ngrams = $ngram_engine->getTermNgramsFromString($ngrams_source); + $conn = $object->establishConnection('w'); + + if ($ngrams) { + $common = queryfx_all( + $conn, + 'SELECT ngram FROM %T WHERE ngram IN (%Ls)', + $engine->getCommonNgramsTableName(), + $ngrams); + $common = ipull($common, 'ngram', 'ngram'); + + foreach ($ngrams as $key => $ngram) { + if (isset($common[$ngram])) { + unset($ngrams[$key]); + continue; + } + + // NOTE: MySQL discards trailing whitespace in CHAR(X) columns. + $trimmed_ngram = rtrim($ngram, ' '); + if (isset($common[$trimmed_ngram])) { + unset($ngrams[$key]); + continue; + } + } + } + $object->openTransaction(); try { - $conn = $object->establishConnection('w'); - $this->deleteOldDocument($engine, $object, $document); + // See T13587. If this document already exists in the index, we try to + // update the existing rows to avoid leaving the ngrams table heavily + // fragmented. - queryfx( + $old_document = queryfx_one( $conn, - 'INSERT INTO %T (objectPHID, isClosed, epochCreated, epochModified, - authorPHID, ownerPHID) VALUES (%s, %d, %d, %d, %ns, %ns)', + 'SELECT id FROM %T WHERE objectPHID = %s', $engine->getDocumentTableName(), - $object->getPHID(), - $is_closed, - $document->getDocumentCreated(), - $document->getDocumentModified(), - $author_phid, - $owner_phid); + $object->getPHID()); + if ($old_document) { + $old_document_id = (int)$old_document['id']; + } else { + $old_document_id = null; + } - $document_id = $conn->getInsertID(); - foreach ($ferret_fields as $ferret_field) { + if ($old_document_id === null) { queryfx( $conn, - 'INSERT INTO %T (documentID, fieldKey, rawCorpus, termCorpus, - normalCorpus) VALUES (%d, %s, %s, %s, %s)', - $engine->getFieldTableName(), - $document_id, - $ferret_field['fieldKey'], - $ferret_field['rawCorpus'], - $ferret_field['termCorpus'], - $ferret_field['normalCorpus']); - } - - if ($ngrams) { - $common = queryfx_all( - $conn, - 'SELECT ngram FROM %T WHERE ngram IN (%Ls)', - $engine->getCommonNgramsTableName(), - $ngrams); - $common = ipull($common, 'ngram', 'ngram'); - - foreach ($ngrams as $key => $ngram) { - if (isset($common[$ngram])) { - unset($ngrams[$key]); - continue; - } - - // NOTE: MySQL discards trailing whitespace in CHAR(X) columns. - $trim_ngram = rtrim($ngram, ' '); - if (isset($common[$ngram])) { - unset($ngrams[$key]); - continue; - } - } + 'INSERT INTO %T (objectPHID, isClosed, epochCreated, epochModified, + authorPHID, ownerPHID) VALUES (%s, %d, %d, %d, %ns, %ns)', + $engine->getDocumentTableName(), + $object->getPHID(), + $is_closed, + $document->getDocumentCreated(), + $document->getDocumentModified(), + $author_phid, + $owner_phid); + $document_id = $conn->getInsertID(); + + $is_new = true; + } else { + $document_id = $old_document_id; + queryfx( + $conn, + 'UPDATE %T + SET + isClosed = %d, + epochCreated = %d, + epochModified = %d, + authorPHID = %ns, + ownerPHID = %ns + WHERE id = %d', + $engine->getDocumentTableName(), + $is_closed, + $document->getDocumentCreated(), + $document->getDocumentModified(), + $author_phid, + $owner_phid, + $document_id); + + $is_new = false; } - if ($ngrams) { - $sql = array(); - foreach ($ngrams as $ngram) { - $sql[] = qsprintf( - $conn, - '(%d, %s)', - $document_id, - $ngram); - } + $this->updateStoredFields( + $conn, + $is_new, + $document_id, + $engine, + $ferret_fields); + + $this->updateStoredNgrams( + $conn, + $is_new, + $document_id, + $engine, + $ngrams); - foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { - queryfx( - $conn, - 'INSERT INTO %T (documentID, ngram) VALUES %LQ', - $engine->getNgramsTableName(), - $chunk); - } - } } catch (Exception $ex) { $object->killTransaction(); throw $ex; + } catch (Throwable $ex) { + $object->killTransaction(); + throw $ex; } $object->saveTransaction(); } + private function updateStoredFields( + AphrontDatabaseConnection $conn, + $is_new, + $document_id, + PhabricatorFerretEngine $engine, + $new_fields) { + + if (!$is_new) { + $old_fields = queryfx_all( + $conn, + 'SELECT * FROM %T WHERE documentID = %d', + $engine->getFieldTableName(), + $document_id); + } else { + $old_fields = array(); + } + + $old_fields = ipull($old_fields, null, 'fieldKey'); + $new_fields = ipull($new_fields, null, 'fieldKey'); + + $delete_rows = array(); + $insert_rows = array(); + $update_rows = array(); + + foreach ($old_fields as $field_key => $old_field) { + if (!isset($new_fields[$field_key])) { + $delete_rows[] = $old_field; + } + } + + $compare_keys = array( + 'rawCorpus', + 'termCorpus', + 'normalCorpus', + ); + + foreach ($new_fields as $field_key => $new_field) { + if (!isset($old_fields[$field_key])) { + $insert_rows[] = $new_field; + continue; + } + + $old_field = $old_fields[$field_key]; + + $same_row = true; + foreach ($compare_keys as $compare_key) { + if ($old_field[$compare_key] !== $new_field[$compare_key]) { + $same_row = false; + break; + } + } + + if ($same_row) { + continue; + } - private function deleteOldDocument( + $new_field['id'] = $old_field['id']; + $update_rows[] = $new_field; + } + + if ($delete_rows) { + queryfx( + $conn, + 'DELETE FROM %T WHERE id IN (%Ld)', + $engine->getFieldTableName(), + ipull($delete_rows, 'id')); + } + + foreach ($update_rows as $update_row) { + queryfx( + $conn, + 'UPDATE %T + SET + rawCorpus = %s, + termCorpus = %s, + normalCorpus = %s + WHERE id = %d', + $engine->getFieldTableName(), + $update_row['rawCorpus'], + $update_row['termCorpus'], + $update_row['normalCorpus'], + $update_row['id']); + } + + foreach ($insert_rows as $insert_row) { + queryfx( + $conn, + 'INSERT INTO %T (documentID, fieldKey, rawCorpus, termCorpus, + normalCorpus) VALUES (%d, %s, %s, %s, %s)', + $engine->getFieldTableName(), + $document_id, + $insert_row['fieldKey'], + $insert_row['rawCorpus'], + $insert_row['termCorpus'], + $insert_row['normalCorpus']); + } + } + + private function updateStoredNgrams( + AphrontDatabaseConnection $conn, + $is_new, + $document_id, PhabricatorFerretEngine $engine, - $object, - PhabricatorSearchAbstractDocument $document) { + $new_ngrams) { - $conn = $object->establishConnection('w'); + if ($is_new) { + $old_ngrams = array(); + } else { + $old_ngrams = queryfx_all( + $conn, + 'SELECT id, ngram FROM %T WHERE documentID = %d', + $engine->getNgramsTableName(), + $document_id); + } + + $old_ngrams = ipull($old_ngrams, 'id', 'ngram'); + $new_ngrams = array_fuse($new_ngrams); + + $delete_ids = array(); + $insert_ngrams = array(); + + // NOTE: MySQL discards trailing whitespace in CHAR(X) columns. + + foreach ($old_ngrams as $ngram => $id) { + if (isset($new_ngrams[$ngram])) { + continue; + } + + $untrimmed_ngram = $ngram.' '; + if (isset($new_ngrams[$untrimmed_ngram])) { + continue; + } + + $delete_ids[] = $id; + } - $old_document = queryfx_one( - $conn, - 'SELECT * FROM %T WHERE objectPHID = %s', - $engine->getDocumentTableName(), - $object->getPHID()); - if (!$old_document) { - return; - } - - $old_id = $old_document['id']; - - queryfx( - $conn, - 'DELETE FROM %T WHERE id = %d', - $engine->getDocumentTableName(), - $old_id); - - queryfx( - $conn, - 'DELETE FROM %T WHERE documentID = %d', - $engine->getFieldTableName(), - $old_id); - - queryfx( - $conn, - 'DELETE FROM %T WHERE documentID = %d', - $engine->getNgramsTableName(), - $old_id); + foreach ($new_ngrams as $ngram) { + if (isset($old_ngrams[$ngram])) { + continue; + } + + $trimmed_ngram = rtrim($ngram, ' '); + if (isset($old_ngrams[$trimmed_ngram])) { + continue; + } + + $insert_ngrams[] = $ngram; + } + + if ($delete_ids) { + $sql = array(); + foreach ($delete_ids as $id) { + $sql[] = qsprintf( + $conn, + '%d', + $id); + } + + foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { + queryfx( + $conn, + 'DELETE FROM %T WHERE id IN (%LQ)', + $engine->getNgramsTableName(), + $chunk); + } + } + + if ($insert_ngrams) { + $sql = array(); + foreach ($insert_ngrams as $ngram) { + $sql[] = qsprintf( + $conn, + '(%d, %s)', + $document_id, + $ngram); + } + + foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { + queryfx( + $conn, + 'INSERT INTO %T (documentID, ngram) VALUES %LQ', + $engine->getNgramsTableName(), + $chunk); + } + } } public function newFerretSearchFunctions() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/index/PhabricatorIndexEngine.php phabricator-0~git20220903/phabricator/src/applications/search/index/PhabricatorIndexEngine.php --- phabricator-0~git20200925/phabricator/src/applications/search/index/PhabricatorIndexEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/index/PhabricatorIndexEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -109,8 +109,10 @@ $rows = queryfx_all( $conn_r, - 'SELECT * FROM %T WHERE objectPHID = %s AND extensionKey IN (%Ls)', - $table->getTableName(), + 'SELECT version, extensionKey + FROM %R + WHERE objectPHID = %s AND extensionKey IN (%Ls)', + $table, $object_phid, $extension_keys); @@ -128,22 +130,35 @@ $table = new PhabricatorSearchIndexVersion(); $conn_w = $table->establishConnection('w'); + $now = PhabricatorTime::getNow(); + + // See T13587. For now, this is just a marker to make it easy to reindex + // documents if some version of the indexing code is later discovered to + // be questionable. + $index_version = '2021-02-16-A'; + $sql = array(); foreach ($versions as $key => $version) { $sql[] = qsprintf( $conn_w, - '(%s, %s, %s)', + '(%s, %s, %s, %s, %d)', $object_phid, $key, - $version); + $version, + $index_version, + $now); } queryfx( $conn_w, - 'INSERT INTO %T (objectPHID, extensionKey, version) + 'INSERT INTO %R (objectPHID, extensionKey, version, + indexVersion, indexEpoch) VALUES %LQ - ON DUPLICATE KEY UPDATE version = VALUES(version)', - $table->getTableName(), + ON DUPLICATE KEY UPDATE + version = VALUES(version), + indexVersion = VALUES(indexVersion), + indexEpoch = VALUES(indexEpoch)', + $table, $sql); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php phabricator-0~git20220903/phabricator/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,9 +8,13 @@ ->setName('index') ->setSynopsis(pht('Build or rebuild search indexes.')) ->setExamples( - "**index** D123\n". - "**index** --type task\n". - "**index** --all") + implode( + "\n", + array( + '**index** D123', + '**index** --all', + '**index** [--type __task__] [--version __version__] ...', + ))) ->setArguments( array( array( @@ -20,6 +24,7 @@ array( 'name' => 'type', 'param' => 'type', + 'repeat' => true, 'help' => pht( 'Object types to reindex, like "task", "commit" or "revision".'), ), @@ -38,6 +43,28 @@ 'incremental update.'), ), array( + 'name' => 'version', + 'param' => 'version', + 'repeat' => true, + 'help' => pht( + 'Reindex objects previously indexed with a particular '. + 'version of the indexer.'), + ), + array( + 'name' => 'min-index-date', + 'param' => 'date', + 'help' => pht( + 'Reindex objects previously indexed on or after a '. + 'given date.'), + ), + array( + 'name' => 'max-index-date', + 'param' => 'date', + 'help' => pht( + 'Reindex objects previously indexed on or before a '. + 'given date.'), + ), + array( 'name' => 'objects', 'wildcard' => true, ), @@ -47,37 +74,46 @@ public function execute(PhutilArgumentParser $args) { $this->validateClusterSearchConfig(); - $console = PhutilConsole::getConsole(); - $is_all = $args->getArg('all'); - $is_type = $args->getArg('type'); $is_force = $args->getArg('force'); - $obj_names = $args->getArg('objects'); + $object_types = $args->getArg('type'); + $index_versions = $args->getArg('version'); - if ($obj_names && ($is_all || $is_type)) { - throw new PhutilArgumentUsageException( - pht( - "You can not name objects to index alongside the '%s' or '%s' flags.", - '--all', - '--type')); - } else if (!$obj_names && !($is_all || $is_type)) { + $min_epoch = $args->getArg('min-index-date'); + if ($min_epoch !== null) { + $min_epoch = $this->parseTimeArgument($min_epoch); + } + + $max_epoch = $args->getArg('max-index-date'); + if ($max_epoch !== null) { + $max_epoch = $this->parseTimeArgument($max_epoch); + } + + $object_names = $args->getArg('objects'); + + $any_constraints = + ($object_names) || + ($object_types) || + ($index_versions) || + ($min_epoch) || + ($max_epoch); + + if ($is_all && $any_constraints) { throw new PhutilArgumentUsageException( pht( - "Provide one of '%s', '%s' or a list of object names.", - '--all', - '--type')); + 'You can not use query constraint flags (like "--version", '. + '"--type", or a list of specific objects) with "--all".')); } - if ($obj_names) { - $phids = $this->loadPHIDsByNames($obj_names); - } else { - $phids = $this->loadPHIDsByTypes($is_type); + if (!$is_all && !$any_constraints) { + throw new PhutilArgumentUsageException( + pht( + 'Provide a list of objects to index (like "D123"), or a set of '. + 'query constraint flags (like "--type"), or "--all" to index '. + 'all objects.')); } - if (!$phids) { - throw new PhutilArgumentUsageException(pht('Nothing to index!')); - } if ($args->getArg('background')) { $is_background = true; @@ -87,21 +123,80 @@ } if (!$is_background) { - echo tsprintf( - "**<bg:blue> %s </bg>** %s\n", + $this->logInfo( pht('NOTE'), pht( - 'Run this workflow with "%s" to queue tasks for the daemon workers.', - '--background')); + 'Run this workflow with "--background" to queue tasks for the '. + 'daemon workers.')); + } + + $this->logInfo( + pht('SELECT'), + pht('Selecting objects to index...')); + + $object_phids = null; + if ($object_names) { + $object_phids = $this->loadPHIDsByNames($object_names); + $object_phids = array_fuse($object_phids); + } + + $type_phids = null; + if ($is_all || $object_types) { + $object_map = $this->getIndexableObjectsByTypes($object_types); + $type_phids = array(); + foreach ($object_map as $object) { + $iterator = new LiskMigrationIterator($object); + foreach ($iterator as $o) { + $type_phids[] = $o->getPHID(); + } + } + $type_phids = array_fuse($type_phids); + } + + $index_phids = null; + if ($index_versions || $min_epoch || $max_epoch) { + $index_phids = $this->loadPHIDsByIndexConstraints( + $index_versions, + $min_epoch, + $max_epoch); + $index_phids = array_fuse($index_phids); + } + + $working_set = null; + $filter_sets = array( + $object_phids, + $type_phids, + $index_phids, + ); + + foreach ($filter_sets as $filter_set) { + if ($filter_set === null) { + continue; + } + + if ($working_set === null) { + $working_set = $filter_set; + continue; + } + + $working_set = array_intersect_key($working_set, $filter_set); } - $groups = phid_group_by_type($phids); - foreach ($groups as $group_type => $group) { - $console->writeOut( - "%s\n", - pht('Indexing %d object(s) of type %s.', count($group), $group_type)); + $phids = array_keys($working_set); + + if (!$phids) { + $this->logWarn( + pht('NO OBJECTS'), + pht('No objects selected to index.')); + return 0; } + $this->logInfo( + pht('INDEXING'), + pht( + 'Indexing %s object(s).', + phutil_count($phids))); + $bar = id(new PhutilConsoleProgressBar()) ->setTotal(count($phids)); @@ -166,8 +261,7 @@ if ($track_skips) { if ($count_updated) { - echo tsprintf( - "**<bg:green> %s </bg>** %s\n", + $this->logOkay( pht('DONE'), pht( 'Updated search indexes for %s document(s).', @@ -175,29 +269,25 @@ } if ($count_skipped) { - echo tsprintf( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('SKIP'), pht( 'Skipped %s documents(s) which have not updated since they were '. 'last indexed.', new PhutilNumber($count_skipped))); - echo tsprintf( - "**<bg:blue> %s </bg>** %s\n", + $this->logInfo( pht('NOTE'), pht( 'Use "--force" to force the index to update these documents.')); } } else if ($is_background) { - echo tsprintf( - "**<bg:green> %s </bg>** %s\n", + $this->logOkay( pht('DONE'), pht( 'Queued %s document(s) for background indexing.', new PhutilNumber(count($phids)))); } else { - echo tsprintf( - "**<bg:green> %s </bg>** %s\n", + $this->logOkay( pht('DONE'), pht( 'Forced search index updates for %s document(s).', @@ -224,62 +314,100 @@ return mpull($objects, 'getPHID'); } - private function loadPHIDsByTypes($type) { + private function getIndexableObjectsByTypes(array $types) { $objects = id(new PhutilClassMapQuery()) ->setAncestorClass('PhabricatorIndexableInterface') ->execute(); - $normalized_type = phutil_utf8_strtolower($type); + $type_map = array(); + $normal_map = array(); + foreach ($types as $type) { + $normalized_type = phutil_utf8_strtolower($type); + $type_map[$type] = $normalized_type; - $matches = array(); + if (isset($normal_map[$normalized_type])) { + $old_type = $normal_map[$normalized_type]; + throw new PhutilArgumentUsageException( + pht( + 'Type specification "%s" duplicates type specification "%s". '. + 'Specify each type only once.', + $type, + $old_type)); + } + + $normal_map[$normalized_type] = $type; + } + + $object_matches = array(); + + $matches_map = array(); + $exact_map = array(); foreach ($objects as $object) { $object_class = get_class($object); - $normalized_class = phutil_utf8_strtolower($object_class); - if ($normalized_class === $normalized_type) { - $matches = array($object_class => $object); - break; + if (!$types) { + $object_matches[$object_class] = $object; + continue; } - if (!strlen($type) || - strpos($normalized_class, $normalized_type) !== false) { - $matches[$object_class] = $object; + $normalized_class = phutil_utf8_strtolower($object_class); + // If a specified type is exactly the name of this class, match it. + if (isset($normal_map[$normalized_class])) { + $object_matches[$object_class] = $object; + $matching_type = $normal_map[$normalized_class]; + $matches_map[$matching_type] = array($object_class); + $exact_map[$matching_type] = true; + continue; } - } - if (!$matches) { - $all_types = array(); - foreach ($objects as $object) { - $all_types[] = get_class($object); - } - sort($all_types); + foreach ($type_map as $type => $normalized_type) { + // If we already have an exact match for this type, don't match it + // as a substring. An indexable "MothObject" should be selectable + // exactly without also selecting "MammothObject". + if (isset($exact_map[$type])) { + continue; + } - throw new PhutilArgumentUsageException( - pht( - 'Type "%s" matches no indexable objects. Supported types are: %s.', - $type, - implode(', ', $all_types))); + // If the selector isn't a substring of the class name, continue. + if (strpos($normalized_class, $normalized_type) === false) { + continue; + } + + $matches_map[$type][] = $object_class; + $object_matches[$object_class] = $object; + } } - if ((count($matches) > 1) && strlen($type)) { - throw new PhutilArgumentUsageException( - pht( - 'Type "%s" matches multiple indexable objects. Use a more '. - 'specific string. Matching object types are: %s.', - $type, - implode(', ', array_keys($matches)))); + $all_types = array(); + foreach ($objects as $object) { + $all_types[] = get_class($object); } + sort($all_types); + $type_list = implode(', ', $all_types); - $phids = array(); - foreach ($matches as $match) { - $iterator = new LiskMigrationIterator($match); - foreach ($iterator as $object) { - $phids[] = $object->getPHID(); + foreach ($type_map as $type => $normalized_type) { + $matches = idx($matches_map, $type); + if (!$matches) { + throw new PhutilArgumentUsageException( + pht( + 'Type "%s" matches no indexable objects. '. + 'Supported types are: %s.', + $type, + $type_list)); + } + + if (count($matches) > 1) { + throw new PhutilArgumentUsageException( + pht( + 'Type "%s" matches multiple indexable objects. Use a more '. + 'specific string. Matching objects are: %s.', + $type, + implode(', ', $matches))); } } - return $phids; + return $object_matches; } private function loadIndexVersions($phid) { @@ -294,4 +422,43 @@ $phid); } + private function loadPHIDsByIndexConstraints( + array $index_versions, + $min_date, + $max_date) { + + $table = new PhabricatorSearchIndexVersion(); + $conn = $table->establishConnection('r'); + + $where = array(); + if ($index_versions) { + $where[] = qsprintf( + $conn, + 'indexVersion IN (%Ls)', + $index_versions); + } + + if ($min_date !== null) { + $where[] = qsprintf( + $conn, + 'indexEpoch >= %d', + $min_date); + } + + if ($max_date !== null) { + $where[] = qsprintf( + $conn, + 'indexEpoch <= %d', + $max_date); + } + + $rows = queryfx_all( + $conn, + 'SELECT DISTINCT objectPHID FROM %R WHERE %LA', + $table, + $where); + + return ipull($rows, 'objectPHID'); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/query/PhabricatorNamedQueryConfigQuery.php phabricator-0~git20220903/phabricator/src/applications/search/query/PhabricatorNamedQueryConfigQuery.php --- phabricator-0~git20200925/phabricator/src/applications/search/query/PhabricatorNamedQueryConfigQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/query/PhabricatorNamedQueryConfigQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorNamedQueryConfig(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/query/PhabricatorNamedQueryQuery.php phabricator-0~git20220903/phabricator/src/applications/search/query/PhabricatorNamedQueryQuery.php --- phabricator-0~git20200925/phabricator/src/applications/search/query/PhabricatorNamedQueryQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/query/PhabricatorNamedQueryQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -32,10 +32,6 @@ return new PhabricatorNamedQuery(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php phabricator-0~git20220903/phabricator/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php --- phabricator-0~git20200925/phabricator/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -40,10 +40,6 @@ return new PhabricatorProfileMenuItemConfiguration(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/search/storage/PhabricatorSearchIndexVersion.php phabricator-0~git20220903/phabricator/src/applications/search/storage/PhabricatorSearchIndexVersion.php --- phabricator-0~git20200925/phabricator/src/applications/search/storage/PhabricatorSearchIndexVersion.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/search/storage/PhabricatorSearchIndexVersion.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,6 +6,8 @@ protected $objectPHID; protected $extensionKey; protected $version; + protected $indexVersion; + protected $indexEpoch; protected function getConfiguration() { return array( @@ -13,12 +15,18 @@ self::CONFIG_COLUMN_SCHEMA => array( 'extensionKey' => 'text64', 'version' => 'text128', + 'indexVersion' => 'bytes12', + 'indexEpoch' => 'epoch', ), self::CONFIG_KEY_SCHEMA => array( 'key_object' => array( 'columns' => array('objectPHID', 'extensionKey'), 'unique' => true, ), + + // NOTE: "bin/search index" may query this table by "indexVersion" or + // "indexEpoch", but this is rare and scanning the table seems fine. + ), ) + parent::getConfiguration(); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php phabricator-0~git20220903/phabricator/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php --- phabricator-0~git20200925/phabricator/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -398,8 +398,9 @@ ->setTitle(pht('Change primary email address?')) ->appendParagraph( pht( - 'If you change your primary address, Phabricator will send all '. + 'If you change your primary address, %s will send all '. 'email to %s.', + PlatformSymbols::getPlatformServerName(), $address)) ->appendParagraph( pht( diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php phabricator-0~git20220903/phabricator/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php --- phabricator-0~git20200925/phabricator/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/panel/PhabricatorExternalEditorSettingsPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -129,7 +129,7 @@ $protocol_table = id(new AphrontTableView($protocol_rows)) ->setNoDataString( pht( - 'Phabricator is not configured to allow any editor protocols.')) + 'No allowed editor protocols are configured.')) ->setHeaders( array( pht('Protocol'), diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php phabricator-0~git20220903/phabricator/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php --- phabricator-0~git20200925/phabricator/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php 2022-06-14 16:29:55.000000000 +0000 @@ -68,8 +68,9 @@ 'span', array(), array( - pht('This browser has not yet granted permission to send desktop '. - 'notifications for this Phabricator instance.'), + pht( + 'Your browser has not yet granted this server permission to send '. + 'desktop notifications.'), phutil_tag('br'), phutil_tag('br'), javelin_tag( @@ -83,13 +84,13 @@ $granted_status = phutil_tag( 'span', array(), - pht('This browser has been granted permission to send desktop '. - 'notifications for this Phabricator instance.')); + pht('Your browser has granted this server permission to send desktop '. + 'notifications.')); $denied_status = phutil_tag( 'span', array(), pht('This browser has denied permission to send desktop notifications '. - 'for this Phabricator instance. Consult your browser settings / '. + 'to this server. Consult your browser settings / '. 'documentation to figure out how to clear this setting, do so, '. 'and then re-visit this page to grant permission.')); @@ -146,7 +147,7 @@ ->setOptions(PhabricatorNotificationsSetting::getOptionsMap()) ->setCaption( pht( - 'Phabricator can send real-time notifications to your web browser '. + 'This server can send real-time notifications to your web browser '. 'or to your desktop. Select where you want to receive these '. 'real-time updates.')) ->initBehavior( diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorAccessibilitySetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorAccessibilitySetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorAccessibilitySetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorAccessibilitySetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -19,8 +19,8 @@ protected function getControlInstructions() { return pht( - 'If you have difficulty reading the Phabricator UI, this setting '. - 'may make Phabricator more accessible.'); + 'If you have difficulty reading the UI, this setting '. + 'may help.'); } public function getSettingDefaultValue() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorDarkConsoleSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorDarkConsoleSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorDarkConsoleSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorDarkConsoleSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -27,7 +27,7 @@ protected function getControlInstructions() { return pht( 'DarkConsole is a debugging console for developing and troubleshooting '. - 'Phabricator applications. After enabling DarkConsole, press the '. + 'applications. After enabling DarkConsole, press the '. '{nav `} key on your keyboard to toggle it on or off.'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEditorSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEditorSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEditorSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEditorSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,8 +21,8 @@ return pht( "Many text editors can be configured as URI handlers for special ". "protocols like `editor://`. If you have installed and configured ". - "such an editor, Phabricator can generate links that you can click ". - "to open files locally.". + "such an editor, some applications can generate links that you can ". + "click to open files locally.". "\n\n". "Provide a URI pattern for building external editor URIs in your ". "environment. For example, if you use TextMate on macOS, the pattern ". @@ -42,7 +42,7 @@ } public function validateTransactionValue($value) { - if (!strlen($value)) { + if (!phutil_nonempty_string($value)) { return; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailFormatSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailFormatSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailFormatSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailFormatSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,8 +22,8 @@ protected function getControlInstructions() { return pht( - 'You can opt to receive plain text email from Phabricator instead '. - 'of HTML email. Plain text email works better with some clients.'); + 'You can opt to receive plain text email instead of HTML email. '. + 'Plain text email works better with some clients.'); } public function getSettingDefaultValue() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailNotificationsSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailNotificationsSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailNotificationsSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailNotificationsSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,7 +22,7 @@ protected function getControlInstructions() { return pht( - 'If you disable **Email Notifications**, Phabricator will never '. + 'If you disable **Email Notifications**, this server will never '. 'send email to notify you about events. This preference overrides '. 'all your other settings.'. "\n\n". diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailSelfActionsSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailSelfActionsSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailSelfActionsSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailSelfActionsSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,7 +22,7 @@ protected function getControlInstructions() { return pht( - 'If you disable **Self Actions**, Phabricator will not notify '. + 'If you disable **Self Actions**, this server will not notify '. 'you about actions you take.'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailStampsSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailStampsSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorEmailStampsSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorEmailStampsSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,7 +22,7 @@ protected function getControlInstructions() { return pht(<<<EOREMARKUP -Phabricator stamps mail with labels like `actor(alice)` which can be used to +Outgoing mail is stamped with labels like `actor(alice)` which can be used to write client mail rules to organize mail. By default, these stamps are sent in an `X-Phabricator-Stamps` header. diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorOlderInlinesSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorOlderInlinesSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorOlderInlinesSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorOlderInlinesSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,7 +22,7 @@ protected function getControlInstructions() { return pht( - 'When a revision is updated, Phabricator attempts to bring inline '. + 'When a revision is updated, this software attempts to bring inline '. 'comments on the older version forward to the new changes. You can '. 'disable this behavior if you prefer comments stay anchored in one '. 'place.'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorSelectSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorSelectSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorSelectSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorSelectSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -47,6 +47,7 @@ } final public function validateTransactionValue($value) { + $value = phutil_string_cast($value); if (!strlen($value)) { return; } @@ -66,11 +67,13 @@ } public function getTransactionNewValue($value) { + $value = phutil_string_cast($value); + if (!strlen($value)) { return null; } - return (string)$value; + return $value; } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorTitleGlyphsSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorTitleGlyphsSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorTitleGlyphsSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorTitleGlyphsSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,9 +22,10 @@ protected function getControlInstructions() { return pht( - 'Phabricator uses unicode glyphs in page titles to provide a compact '. - 'representation of the current application. You can substitute plain '. - 'text instead if these glyphs do not display on your system.'); + 'Some applications use unicode glyphs in page titles to provide a '. + 'compact representation of the current application. You can '. + 'substitute plain text instead if these glyphs do not display on '. + 'your system.'); } public function getSettingDefaultValue() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorTranslationSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorTranslationSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorTranslationSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorTranslationSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -23,7 +23,7 @@ protected function getControlInstructions() { return pht( - 'Choose which language you would like the Phabricator UI to use.'); + 'Choose which language you would like the UI to use.'); } public function assertValidValue($value) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorUnifiedDiffsSetting.php phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorUnifiedDiffsSetting.php --- phabricator-0~git20200925/phabricator/src/applications/settings/setting/PhabricatorUnifiedDiffsSetting.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/setting/PhabricatorUnifiedDiffsSetting.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,8 +22,8 @@ protected function getControlInstructions() { return pht( - 'Phabricator normally shows diffs in a side-by-side layout on large '. - 'screens and automatically switches to a unified view on small '. + 'Diffs are normally shown in a side-by-side layout on large '. + 'screens and automatically switched to a unified view on small '. 'screens (like mobile phones). If you prefer unified diffs even on '. 'large screens, you can select them for use on all displays.'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/settings/storage/PhabricatorUserPreferences.php phabricator-0~git20220903/phabricator/src/applications/settings/storage/PhabricatorUserPreferences.php --- phabricator-0~git20200925/phabricator/src/applications/settings/storage/PhabricatorUserPreferences.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/settings/storage/PhabricatorUserPreferences.php 2022-06-14 16:29:55.000000000 +0000 @@ -219,11 +219,15 @@ } } - switch ($this->getBuiltinKey()) { - case self::BUILTIN_GLOBAL_DEFAULT: - // NOTE: Without this policy exception, the logged-out viewer can not - // see global preferences. - return true; + $builtin_key = $this->getBuiltinKey(); + + $is_global = ($builtin_key === self::BUILTIN_GLOBAL_DEFAULT); + $is_view = ($capability === PhabricatorPolicyCapability::CAN_VIEW); + + if ($is_global && $is_view) { + // NOTE: Without this policy exception, the logged-out viewer can not + // see global preferences. + return true; } return false; diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/constants/SlowvotePollResponseVisibility.php phabricator-0~git20220903/phabricator/src/applications/slowvote/constants/SlowvotePollResponseVisibility.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/constants/SlowvotePollResponseVisibility.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/constants/SlowvotePollResponseVisibility.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,75 @@ +<?php + +final class SlowvotePollResponseVisibility + extends Phobject { + + const RESPONSES_VISIBLE = 'visible'; + const RESPONSES_VOTERS = 'voters'; + const RESPONSES_OWNER = 'owner'; + + private $key; + + public static function newResponseVisibilityObject($key) { + $object = new self(); + $object->key = $key; + return $object; + } + + public function getKey() { + return $this->key; + } + + public static function getAll() { + $map = self::getMap(); + + $result = array(); + foreach ($map as $key => $spec) { + $result[$key] = self::newResponseVisibilityObject($key); + } + + return $result; + } + + public function getName() { + $name = $this->getProperty('name'); + + if ($name === null) { + $name = pht('Unknown ("%s")', $this->getKey()); + } + + return $name; + } + + public function getNameForEdit() { + $name = $this->getProperty('name.edit'); + + if ($name === null) { + $name = pht('Unknown ("%s")', $this->getKey()); + } + + return $name; + } + + private function getProperty($key, $default = null) { + $spec = idx(self::getMap(), $this->getKey(), array()); + return idx($spec, $key, $default); + } + + private static function getMap() { + return array( + self::RESPONSES_VISIBLE => array( + 'name' => pht('Always Visible'), + 'name.edit' => pht('Anyone can see the responses'), + ), + self::RESPONSES_VOTERS => array( + 'name' => pht('Voters'), + 'name.edit' => pht('Require a vote to see the responses'), + ), + self::RESPONSES_OWNER => array( + 'name' => pht('Owner'), + 'name.edit' => pht('Only the poll owner can see the responses'), + ), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/constants/SlowvotePollStatus.php phabricator-0~git20220903/phabricator/src/applications/slowvote/constants/SlowvotePollStatus.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/constants/SlowvotePollStatus.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/constants/SlowvotePollStatus.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,76 @@ +<?php + +final class SlowvotePollStatus + extends Phobject { + + const STATUS_OPEN = 'open'; + const STATUS_CLOSED = 'closed'; + + private $key; + + public static function newStatusObject($key) { + $object = new self(); + $object->key = $key; + return $object; + } + + public function getKey() { + return $this->key; + } + + public static function getAll() { + $map = self::getMap(); + + $result = array(); + foreach ($map as $key => $spec) { + $result[$key] = self::newStatusObject($key); + } + + return $result; + } + + public function getName() { + $name = $this->getProperty('name'); + + if ($name === null) { + $name = pht('Unknown ("%s")', $this->getKey()); + } + + return $name; + } + + public function getHeaderTagIcon() { + return $this->getProperty('header.tag.icon'); + } + + public function getHeaderTagColor() { + return $this->getProperty('header.tag.color'); + } + + public function getTransactionIcon() { + return $this->getProperty('transaction.icon'); + } + + private function getProperty($key, $default = null) { + $spec = idx(self::getMap(), $this->getKey(), array()); + return idx($spec, $key, $default); + } + + private static function getMap() { + return array( + self::STATUS_OPEN => array( + 'name' => pht('Open'), + 'header.tag.icon' => 'fa-square-o', + 'header.tag.color' => 'bluegrey', + 'transaction.icon' => 'fa-pencil', + ), + self::STATUS_CLOSED => array( + 'name' => pht('Closed'), + 'header.tag.icon' => 'fa-ban', + 'header.tag.color' => 'indigo', + 'transaction.icon' => 'fa-ban', + ), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/constants/SlowvotePollVotingMethod.php phabricator-0~git20220903/phabricator/src/applications/slowvote/constants/SlowvotePollVotingMethod.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/constants/SlowvotePollVotingMethod.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/constants/SlowvotePollVotingMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,70 @@ +<?php + +final class SlowvotePollVotingMethod + extends Phobject { + + const METHOD_PLURALITY = 'plurality'; + const METHOD_APPROVAL = 'approval'; + + private $key; + + public static function newVotingMethodObject($key) { + $object = new self(); + $object->key = $key; + return $object; + } + + public function getKey() { + return $this->key; + } + + public static function getAll() { + $map = self::getMap(); + + $result = array(); + foreach ($map as $key => $spec) { + $result[$key] = self::newVotingMethodObject($key); + } + + return $result; + } + + public function getName() { + $name = $this->getProperty('name'); + + if ($name === null) { + $name = pht('Unknown ("%s")', $this->getKey()); + } + + return $name; + } + + public function getNameForEdit() { + $name = $this->getProperty('name.edit'); + + if ($name === null) { + $name = pht('Unknown ("%s")', $this->getKey()); + } + + return $name; + } + + private function getProperty($key, $default = null) { + $spec = idx(self::getMap(), $this->getKey(), array()); + return idx($spec, $key, $default); + } + + private static function getMap() { + return array( + self::METHOD_PLURALITY => array( + 'name' => pht('Plurality'), + 'name.edit' => pht('Plurality (Single Choice)'), + ), + self::METHOD_APPROVAL => array( + 'name' => pht('Approval'), + 'name.edit' => pht('Approval (Multiple Choice)'), + ), + ); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php 2022-06-14 16:29:55.000000000 +0000 @@ -20,20 +20,20 @@ return new Aphront404Response(); } - $close_uri = '/V'.$poll->getID(); + $close_uri = $poll->getURI(); if ($request->isFormPost()) { - if ($poll->getIsClosed()) { - $new_status = 0; + if ($poll->isClosed()) { + $new_status = SlowvotePollStatus::STATUS_OPEN; } else { - $new_status = 1; + $new_status = SlowvotePollStatus::STATUS_CLOSED; } $xactions = array(); $xactions[] = id(new PhabricatorSlowvoteTransaction()) ->setTransactionType( - PhabricatorSlowvoteCloseTransaction::TRANSACTIONTYPE) + PhabricatorSlowvoteStatusTransaction::TRANSACTIONTYPE) ->setNewValue($new_status); id(new PhabricatorSlowvoteEditor()) @@ -46,7 +46,7 @@ return id(new AphrontRedirectResponse())->setURI($close_uri); } - if ($poll->getIsClosed()) { + if ($poll->isClosed()) { $title = pht('Reopen Poll'); $content = pht('Are you sure you want to reopen the poll?'); $submit = pht('Reopen'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php 2022-06-14 16:29:55.000000000 +0000 @@ -49,7 +49,7 @@ if ($request->isFormPost()) { $v_question = $request->getStr('question'); $v_description = $request->getStr('description'); - $v_responses = (int)$request->getInt('responses'); + $v_responses = $request->getStr('responses'); $v_shuffle = (int)$request->getBool('shuffle'); $v_view_policy = $request->getStr('viewPolicy'); $v_projects = $request->getArr('projects'); @@ -57,7 +57,7 @@ $v_space = $request->getStr('spacePHID'); if ($is_new) { - $poll->setMethod($request->getInt('method')); + $poll->setMethod($request->getStr('method')); } if (!strlen($v_question)) { @@ -189,21 +189,33 @@ } } - $poll_type_options = array( - PhabricatorSlowvotePoll::METHOD_PLURALITY => - pht('Plurality (Single Choice)'), - PhabricatorSlowvotePoll::METHOD_APPROVAL => - pht('Approval (Multiple Choice)'), - ); - - $response_type_options = array( - PhabricatorSlowvotePoll::RESPONSES_VISIBLE - => pht('Allow anyone to see the responses'), - PhabricatorSlowvotePoll::RESPONSES_VOTERS - => pht('Require a vote to see the responses'), - PhabricatorSlowvotePoll::RESPONSES_OWNER - => pht('Only I can see the responses'), - ); + $vote_type_map = SlowvotePollVotingMethod::getAll(); + $vote_type_options = mpull($vote_type_map, 'getNameForEdit'); + + $method = $poll->getMethod(); + if (!isset($vote_type_options[$method])) { + $method_object = + SlowvotePollVotingMethod::newVotingMethodObject( + $method); + + $vote_type_options = array( + $method => $method_object->getNameForEdit(), + ) + $vote_type_options; + } + + $response_type_map = SlowvotePollResponseVisibility::getAll(); + $response_type_options = mpull($response_type_map, 'getNameForEdit'); + + $visibility = $poll->getResponseVisibility(); + if (!isset($response_type_options[$visibility])) { + $visibility_object = + SlowvotePollResponseVisibility::newResponseVisibilityObject( + $visibility); + + $response_type_options = array( + $visibility => $visibility_object->getNameForEdit(), + ) + $response_type_options; + } if ($is_new) { $form->appendChild( @@ -211,12 +223,12 @@ ->setLabel(pht('Vote Type')) ->setName('method') ->setValue($poll->getMethod()) - ->setOptions($poll_type_options)); + ->setOptions($vote_type_options)); } else { $form->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Vote Type')) - ->setValue(idx($poll_type_options, $poll->getMethod()))); + ->setValue(idx($vote_type_options, $poll->getMethod()))); } if ($is_new) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvotePollController.php phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvotePollController.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvotePollController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvotePollController.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,9 +35,11 @@ )); } - $header_icon = $poll->getIsClosed() ? 'fa-ban' : 'fa-square-o'; - $header_name = $poll->getIsClosed() ? pht('Closed') : pht('Open'); - $header_color = $poll->getIsClosed() ? 'indigo' : 'bluegrey'; + $status = $poll->getStatusObject(); + + $header_icon = $status->getHeaderTagIcon(); + $header_color = $status->getHeaderTagColor(); + $header_name = $status->getName(); $header = id(new PHUIHeaderView()) ->setHeader($poll->getQuestion()) @@ -50,7 +52,7 @@ $subheader = $this->buildSubheaderView($poll); $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb('V'.$poll->getID()); + $crumbs->addTextCrumb($poll->getMonogram()); $crumbs->setBorder(true); $timeline = $this->buildTransactionTimeline( @@ -71,7 +73,11 @@ ->setMainColumn($poll_content); return $this->newPage() - ->setTitle('V'.$poll->getID().' '.$poll->getQuestion()) + ->setTitle( + pht( + '%s %s', + $poll->getMonogram(), + $poll->getQuestion())) ->setCrumbs($crumbs) ->setPageObjectPHIDs(array($poll->getPHID())) ->appendChild($view); @@ -87,7 +93,7 @@ $curtain = $this->newCurtainView($poll); - $is_closed = $poll->getIsClosed(); + $is_closed = $poll->isClosed(); $close_poll_text = $is_closed ? pht('Reopen Poll') : pht('Close Poll'); $close_poll_icon = $is_closed ? 'fa-check' : 'fa-ban'; diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ return new Aphront404Response(); } - if ($poll->getIsClosed()) { + if ($poll->isClosed()) { return new Aphront400Response(); } @@ -35,7 +35,7 @@ $votes = array_fuse($votes); $method = $poll->getMethod(); - $is_plurality = ($method == PhabricatorSlowvotePoll::METHOD_PLURALITY); + $is_plurality = ($method == SlowvotePollVotingMethod::METHOD_PLURALITY); if (!$votes) { if ($is_plurality) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php phabricator-0~git20220903/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,7 +7,7 @@ private $phids; private $authorPHIDs; private $withVotesByViewer; - private $isClosed; + private $statuses; private $needOptions; private $needChoices; @@ -33,8 +33,8 @@ return $this; } - public function withIsClosed($with_closed) { - $this->isClosed = $with_closed; + public function withStatuses(array $statuses) { + $this->statuses = $statuses; return $this; } @@ -57,10 +57,6 @@ return new PhabricatorSlowvotePoll(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $polls) { assert_instances_of($polls, 'PhabricatorSlowvotePoll'); @@ -141,12 +137,13 @@ $this->authorPHIDs); } - if ($this->isClosed !== null) { + if ($this->statuses !== null) { $where[] = qsprintf( $conn, - 'p.isClosed = %d', - (int)$this->isClosed); + 'p.status IN (%Ls)', + $this->statuses); } + return $where; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php phabricator-0~git20220903/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,14 +26,8 @@ $query->withAuthorPHIDs($map['authorPHIDs']); } - $statuses = $map['statuses']; - if (count($statuses) == 1) { - $status = head($statuses); - if ($status == 'open') { - $query->withIsClosed(false); - } else { - $query->withIsClosed(true); - } + if ($map['statuses']) { + $query->withStatuses($map['statuses']); } return $query; @@ -41,6 +35,9 @@ protected function buildCustomSearchFields() { + $status_options = SlowvotePollStatus::getAll(); + $status_options = mpull($status_options, 'getName'); + return array( id(new PhabricatorUsersSearchField()) ->setKey('authorPHIDs') @@ -61,11 +58,7 @@ id(new PhabricatorSearchCheckboxesField()) ->setKey('statuses') ->setLabel(pht('Statuses')) - ->setOptions( - array( - 'open' => pht('Open'), - 'closed' => pht('Closed'), - )), + ->setOptions($status_options), ); } @@ -137,12 +130,12 @@ $item = id(new PHUIObjectItemView()) ->setUser($viewer) ->setObject($poll) - ->setObjectName('V'.$poll->getID()) + ->setObjectName($poll->getMonogram()) ->setHeader($poll->getQuestion()) - ->setHref('/V'.$poll->getID()) + ->setHref($poll->getURI()) ->addIcon('none', $date_created); - if ($poll->getIsClosed()) { + if ($poll->isClosed()) { $item->setStatusIcon('fa-ban grey'); $item->setDisabled(true); } else { diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php phabricator-0~git20220903/phabricator/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,6 +1,7 @@ <?php -final class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO +final class PhabricatorSlowvotePoll + extends PhabricatorSlowvoteDAO implements PhabricatorApplicationTransactionInterface, PhabricatorPolicyInterface, @@ -12,22 +13,14 @@ PhabricatorSpacesInterface, PhabricatorConduitResultInterface { - const RESPONSES_VISIBLE = 0; - const RESPONSES_VOTERS = 1; - const RESPONSES_OWNER = 2; - - const METHOD_PLURALITY = 0; - const METHOD_APPROVAL = 1; - protected $question; protected $description; protected $authorPHID; - protected $responseVisibility = 0; + protected $responseVisibility; protected $shuffle = 0; protected $method; - protected $mailKey; protected $viewPolicy; - protected $isClosed = 0; + protected $status; protected $spacePHID; private $options = self::ATTACHABLE; @@ -43,10 +36,16 @@ $view_policy = $app->getPolicy( PhabricatorSlowvoteDefaultViewCapability::CAPABILITY); + $default_responses = SlowvotePollResponseVisibility::RESPONSES_VISIBLE; + $default_method = SlowvotePollVotingMethod::METHOD_PLURALITY; + return id(new PhabricatorSlowvotePoll()) ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy) - ->setSpacePHID($actor->getDefaultSpacePHID()); + ->setSpacePHID($actor->getDefaultSpacePHID()) + ->setStatus(SlowvotePollStatus::STATUS_OPEN) + ->setMethod($default_method) + ->setResponseVisibility($default_responses); } protected function getConfiguration() { @@ -54,26 +53,27 @@ self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( 'question' => 'text255', - 'responseVisibility' => 'uint32', + 'responseVisibility' => 'text32', 'shuffle' => 'bool', - 'method' => 'uint32', + 'method' => 'text32', 'description' => 'text', - 'isClosed' => 'bool', - 'mailKey' => 'bytes20', + 'status' => 'text32', ), self::CONFIG_KEY_SCHEMA => array( - 'key_phid' => null, - 'phid' => array( - 'columns' => array('phid'), - 'unique' => true, - ), ), ) + parent::getConfiguration(); } - public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - PhabricatorSlowvotePollPHIDType::TYPECONST); + public function getPHIDType() { + return PhabricatorSlowvotePollPHIDType::TYPECONST; + } + + public function getStatusObject() { + return SlowvotePollStatus::newStatusObject($this->getStatus()); + } + + public function isClosed() { + return ($this->getStatus() == SlowvotePollStatus::STATUS_CLOSED); } public function getOptions() { @@ -117,13 +117,6 @@ return '/'.$this->getMonogram(); } - public function save() { - if (!$this->getMailKey()) { - $this->setMailKey(Filesystem::readRandomCharacters(20)); - } - return parent::save(); - } - /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php phabricator-0~git20220903/phabricator/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -30,7 +30,7 @@ case PhabricatorSlowvoteQuestionTransaction::TRANSACTIONTYPE: case PhabricatorSlowvoteDescriptionTransaction::TRANSACTIONTYPE: case PhabricatorSlowvoteShuffleTransaction::TRANSACTIONTYPE: - case PhabricatorSlowvoteCloseTransaction::TRANSACTIONTYPE: + case PhabricatorSlowvoteStatusTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_DETAILS; break; case PhabricatorSlowvoteResponsesTransaction::TRANSACTIONTYPE: diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/view/SlowvoteEmbedView.php phabricator-0~git20220903/phabricator/src/applications/slowvote/view/SlowvoteEmbedView.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/view/SlowvoteEmbedView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/view/SlowvoteEmbedView.php 2022-06-14 16:29:55.000000000 +0000 @@ -75,16 +75,16 @@ $description, ); + $quip = pht('Voting improves cardiovascular endurance.'); + $vis = $poll->getResponseVisibility(); if ($this->areResultsVisible()) { - if ($vis == PhabricatorSlowvotePoll::RESPONSES_OWNER) { + if ($vis == SlowvotePollResponseVisibility::RESPONSES_OWNER) { $quip = pht('Only you can see the results.'); - } else { - $quip = pht('Voting improves cardiovascular endurance.'); } - } else if ($vis == PhabricatorSlowvotePoll::RESPONSES_VOTERS) { + } else if ($vis == SlowvotePollResponseVisibility::RESPONSES_VOTERS) { $quip = pht('You must vote to see the results.'); - } else if ($vis == PhabricatorSlowvotePoll::RESPONSES_OWNER) { + } else if ($vis == SlowvotePollResponseVisibility::RESPONSES_OWNER) { $quip = pht('Only the author can see the results.'); } @@ -95,7 +95,7 @@ ), $quip); - if ($poll->getIsClosed()) { + if ($poll->isClosed()) { $submit = null; } else { $submit = phutil_tag( @@ -224,11 +224,11 @@ private function renderControl(PhabricatorSlowvoteOption $option, $selected) { $types = array( - PhabricatorSlowvotePoll::METHOD_PLURALITY => 'radio', - PhabricatorSlowvotePoll::METHOD_APPROVAL => 'checkbox', + SlowvotePollVotingMethod::METHOD_PLURALITY => 'radio', + SlowvotePollVotingMethod::METHOD_APPROVAL => 'checkbox', ); - $closed = $this->getPoll()->getIsClosed(); + $closed = $this->getPoll()->isClosed(); return phutil_tag( 'input', @@ -301,13 +301,17 @@ $percent = sprintf('%d%%', $count ? 100 * $choices / $count : 0); - switch ($poll->getMethod()) { - case PhabricatorSlowvotePoll::METHOD_PLURALITY: + $method = $poll->getMethod(); + switch ($method) { + case SlowvotePollVotingMethod::METHOD_PLURALITY: $status = pht('%s (%d / %d)', $percent, $choices, $count); break; - case PhabricatorSlowvotePoll::METHOD_APPROVAL: + case SlowvotePollVotingMethod::METHOD_APPROVAL: $status = pht('%s Approval (%d / %d)', $percent, $choices, $count); break; + default: + $status = pht('Unknown ("%s")', $method); + break; } return phutil_tag( @@ -321,15 +325,19 @@ private function areResultsVisible() { $poll = $this->getPoll(); - $vis = $poll->getResponseVisibility(); - if ($vis == PhabricatorSlowvotePoll::RESPONSES_VISIBLE) { + $visibility = $poll->getResponseVisibility(); + if ($visibility == SlowvotePollResponseVisibility::RESPONSES_VISIBLE) { return true; - } else if ($vis == PhabricatorSlowvotePoll::RESPONSES_OWNER) { - return ($poll->getAuthorPHID() == $this->getUser()->getPHID()); - } else { - $choices = mgroup($poll->getChoices(), 'getAuthorPHID'); - return (bool)idx($choices, $this->getUser()->getPHID()); } + + $viewer = $this->getViewer(); + + if ($visibility == SlowvotePollResponseVisibility::RESPONSES_OWNER) { + return ($poll->getAuthorPHID() === $viewer->getPHID()); + } + + $choices = mgroup($poll->getChoices(), 'getAuthorPHID'); + return (bool)idx($choices, $viewer->getPHID()); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteCloseTransaction.php phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteCloseTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteCloseTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteCloseTransaction.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -<?php - -final class PhabricatorSlowvoteCloseTransaction - extends PhabricatorSlowvoteTransactionType { - - const TRANSACTIONTYPE = 'vote:close'; - - public function generateOldValue($object) { - return (bool)$object->getIsClosed(); - } - - public function generateNewValue($object, $value) { - return (bool)$value; - } - - public function applyInternalEffects($object, $value) { - $object->setIsClosed((int)$value); - } - - public function getTitle() { - $new = $this->getNewValue(); - - if ($new) { - return pht( - '%s closed this poll.', - $this->renderAuthor()); - } else { - return pht( - '%s reopened this poll.', - $this->renderAuthor()); - } - } - - public function getTitleForFeed() { - $new = $this->getNewValue(); - - if ($new) { - return pht( - '%s closed %s.', - $this->renderAuthor(), - $this->renderObject()); - } else { - return pht( - '%s reopened %s.', - $this->renderAuthor(), - $this->renderObject()); - } - } - - public function getIcon() { - $new = $this->getNewValue(); - - if ($new) { - return 'fa-ban'; - } else { - return 'fa-pencil'; - } - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteResponsesTransaction.php phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteResponsesTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteResponsesTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteResponsesTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,7 +6,11 @@ const TRANSACTIONTYPE = 'vote:responses'; public function generateOldValue($object) { - return (int)$object->getResponseVisibility(); + return (string)$object->getResponseVisibility(); + } + + public function generateNewValue($object, $value) { + return (string)$value; } public function applyInternalEffects($object, $value) { @@ -14,18 +18,38 @@ } public function getTitle() { - // TODO: This could be more detailed + $old_name = $this->getOldResponseVisibilityObject()->getName(); + $new_name = $this->getNewResponseVisibilityObject()->getName(); + return pht( - '%s changed who can see the responses.', - $this->renderAuthor()); + '%s changed who can see the responses from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old_name), + $this->renderValue($new_name)); } public function getTitleForFeed() { - // TODO: This could be more detailed + $old_name = $this->getOldResponseVisibilityObject()->getName(); + $new_name = $this->getNewResponseVisibilityObject()->getName(); + return pht( - '%s changed who can see the responses of %s.', + '%s changed who can see the responses of %s from %s to %s.', $this->renderAuthor(), - $this->renderObject()); + $this->renderObject(), + $this->renderValue($old_name), + $this->renderValue($new_name)); + } + + private function getOldResponseVisibilityObject() { + return $this->newResponseVisibilityObject($this->getOldValue()); + } + + private function getNewResponseVisibilityObject() { + return $this->newResponseVisibilityObject($this->getNewValue()); + } + + private function newResponseVisibilityObject($value) { + return SlowvotePollResponseVisibility::newResponseVisibilityObject($value); } } diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteStatusTransaction.php phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteStatusTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteStatusTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteStatusTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,60 @@ +<?php + +final class PhabricatorSlowvoteStatusTransaction + extends PhabricatorSlowvoteTransactionType { + + const TRANSACTIONTYPE = 'vote:status'; + + public function generateOldValue($object) { + return (string)$object->getStatus(); + } + + public function generateNewValue($object, $value) { + return (string)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + $old_name = $this->getOldStatusObject()->getName(); + $new_name = $this->getNewStatusObject()->getName(); + + return pht( + '%s changed the status of this poll from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old_name), + $this->renderValue($new_name)); + } + + public function getTitleForFeed() { + $old_name = $this->getOldStatusObject()->getName(); + $new_name = $this->getNewStatusObject()->getName(); + + + return pht( + '%s changed the status of %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderValue($old_name), + $this->renderValue($new_name)); + } + + public function getIcon() { + return $this->getNewStatusObject()->getTransactionIcon(); + } + + private function getOldStatusObject() { + return $this->newStatusObject($this->getOldValue()); + } + + private function getNewStatusObject() { + return $this->newStatusObject($this->getNewValue()); + } + + private function newStatusObject($value) { + return SlowvotePollStatus::newStatusObject($value); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteVotingMethodTransaction.php phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteVotingMethodTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteVotingMethodTransaction.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/slowvote/xaction/PhabricatorSlowvoteVotingMethodTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,55 @@ +<?php + +final class PhabricatorSlowvoteVotingMethodTransaction + extends PhabricatorSlowvoteTransactionType { + + const TRANSACTIONTYPE = 'vote:method'; + + public function generateOldValue($object) { + return (string)$object->getMethod(); + } + + public function generateNewValue($object, $value) { + return (string)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setMethod($value); + } + + public function getTitle() { + $old_name = $this->getOldVotingMethodObject()->getName(); + $new_name = $this->getNewVotingMethodObject()->getName(); + + return pht( + '%s changed the voting method from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old_name), + $this->renderValue($new_name)); + } + + public function getTitleForFeed() { + $old_name = $this->getOldVotingMethodObject()->getName(); + $new_name = $this->getNewVotingMethodObject()->getName(); + + return pht( + '%s changed the voting method of %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderValue($old_name), + $this->renderValue($new_name)); + } + + private function getOldVotingMethodObject() { + return $this->newVotingMethodObject($this->getOldValue()); + } + + private function getNewVotingMethodObject() { + return $this->newVotingMethodObject($this->getNewValue()); + } + + private function newVotingMethodObject($value) { + return SlowvotePollVotingMethod::newVotingMethodObject($value); + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php phabricator-0~git20220903/phabricator/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php --- phabricator-0~git20200925/phabricator/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -36,8 +36,8 @@ return 'PhabricatorSpacesApplication'; } - protected function loadPage() { - return $this->loadStandardPage(new PhabricatorSpacesNamespace()); + public function newResultObject() { + return new PhabricatorSpacesNamespace(); } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/subscriptions/command/PhabricatorSubscriptionsSubscribeEmailCommand.php phabricator-0~git20220903/phabricator/src/applications/subscriptions/command/PhabricatorSubscriptionsSubscribeEmailCommand.php --- phabricator-0~git20200925/phabricator/src/applications/subscriptions/command/PhabricatorSubscriptionsSubscribeEmailCommand.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/subscriptions/command/PhabricatorSubscriptionsSubscribeEmailCommand.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,8 +26,7 @@ 'command has no effect if you do not specify any subscribers.'. "\n\n". 'Users who are CC\'d on the email itself are also automatically '. - 'subscribed if Phabricator knows which accounts are linked to their '. - 'email addresses.', + 'subscribed if their addresses are associated with a known account.', '!subscribe alincoln #ios'); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php phabricator-0~git20220903/phabricator/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php --- phabricator-0~git20200925/phabricator/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -62,17 +62,30 @@ $handles = $viewer->loadHandles($visible_phids); } + PhabricatorPolicyFilterSet::loadHandleViewCapabilities( + $viewer, + $handles, + array($object)); + $ref_list = id(new PHUICurtainObjectRefListView()) ->setViewer($viewer) ->setEmptyMessage(pht('None')); foreach ($visible_phids as $phid) { + $handle = $handles[$phid]; + $ref = $ref_list->newObjectRefView() - ->setHandle($handles[$phid]); + ->setHandle($handle); if ($phid === $viewer_phid) { $ref->setHighlighted(true); } + + if ($handle->hasCapabilities()) { + if (!$handle->hasViewCapability($object)) { + $ref->setExiled(true); + } + } } if ($show_all) { diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/application/PhabricatorSystemApplication.php phabricator-0~git20220903/phabricator/src/applications/system/application/PhabricatorSystemApplication.php --- phabricator-0~git20200925/phabricator/src/applications/system/application/PhabricatorSystemApplication.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/application/PhabricatorSystemApplication.php 2022-06-14 16:29:55.000000000 +0000 @@ -25,7 +25,7 @@ '/status/' => 'PhabricatorStatusController', '/debug/' => 'PhabricatorDebugController', '/favicon.ico' => 'PhabricatorFaviconController', - '/robots.txt' => 'PhabricatorRobotsController', + '/robots.txt' => 'PhabricatorRobotsPlatformController', '/services/' => array( 'encoding/' => 'PhabricatorSystemSelectEncodingController', 'highlight/' => 'PhabricatorSystemSelectHighlightController', @@ -38,4 +38,12 @@ ); } + public function getResourceRoutes() { + return array( + '/status/' => 'PhabricatorStatusController', + '/favicon.ico' => 'PhabricatorFaviconController', + '/robots.txt' => 'PhabricatorRobotsResourceController', + ); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/controller/PhabricatorRobotsController.php phabricator-0~git20220903/phabricator/src/applications/system/controller/PhabricatorRobotsController.php --- phabricator-0~git20200925/phabricator/src/applications/system/controller/PhabricatorRobotsController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/controller/PhabricatorRobotsController.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -<?php - -final class PhabricatorRobotsController extends PhabricatorController { - - public function shouldRequireLogin() { - return false; - } - - public function processRequest() { - $out = array(); - - // Prevent indexing of '/diffusion/', since the content is not generally - // useful to index, web spiders get stuck scraping the history of every - // file, and much of the content is Ajaxed in anyway so spiders won't even - // see it. These pages are also relatively expensive to generate. - - // Note that this still allows commits (at '/rPxxxxx') to be indexed. - // They're probably not hugely useful, but suffer fewer of the problems - // Diffusion suffers and are hard to omit with 'robots.txt'. - - $out[] = 'User-Agent: *'; - $out[] = 'Disallow: /diffusion/'; - $out[] = 'Disallow: /source/'; - - // Add a small crawl delay (number of seconds between requests) for spiders - // which respect it. The intent here is to prevent spiders from affecting - // performance for users. The possible cost is slower indexing, but that - // seems like a reasonable tradeoff, since most Phabricator installs are - // probably not hugely concerned about cutting-edge SEO. - $out[] = 'Crawl-delay: 1'; - - $content = implode("\n", $out)."\n"; - - return id(new AphrontPlainTextResponse()) - ->setContent($content) - ->setCacheDurationInSeconds(phutil_units('2 hours in seconds')) - ->setCanCDN(true); - } -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/controller/PhabricatorSystemReadOnlyController.php phabricator-0~git20220903/phabricator/src/applications/system/controller/PhabricatorSystemReadOnlyController.php --- phabricator-0~git20200925/phabricator/src/applications/system/controller/PhabricatorSystemReadOnlyController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/controller/PhabricatorSystemReadOnlyController.php 2022-06-14 16:29:55.000000000 +0000 @@ -16,7 +16,7 @@ case PhabricatorEnv::READONLY_CONFIG: $title = pht('Administrative Read-Only Mode'); $body[] = pht( - 'An administrator has placed Phabricator into read-only mode.'); + 'An administrator has placed this server into read-only mode.'); $body[] = pht( 'This mode may be used to perform temporary maintenance, test '. 'configuration, or archive an installation permanently.'); @@ -24,8 +24,9 @@ 'Read-only mode was enabled by the explicit action of a human '. 'administrator, so you can get more information about why it '. 'has been turned on by rolling your chair away from your desk and '. - 'yelling "Hey! Why is Phabricator in read-only mode??!" using '. - 'your very loudest outside voice.'); + 'yelling "Hey! Why is %s in read-only mode??!" using '. + 'your very loudest outside voice.', + PlatformSymbols::getPlatformServerSymbol()); $body[] = pht( 'This mode is active because it is enabled in the configuration '. 'option "%s".', @@ -35,9 +36,9 @@ case PhabricatorEnv::READONLY_MASTERLESS: $title = pht('No Writable Database'); $body[] = pht( - 'Phabricator is currently configured with no writable ("master") '. + 'This server is currently configured with no writable ("master") '. 'database, so it can not write new information anywhere. '. - 'Phabricator will run in read-only mode until an administrator '. + 'This server will run in read-only mode until an administrator '. 'reconfigures it with a writable database.'); $body[] = pht( 'This usually occurs when an administrator is actively working on '. @@ -52,17 +53,17 @@ case PhabricatorEnv::READONLY_UNREACHABLE: $title = pht('Unable to Reach Master'); $body[] = pht( - 'Phabricator was unable to connect to the writable ("master") '. + 'This server was unable to connect to the writable ("master") '. 'database while handling this request, and automatically degraded '. 'into read-only mode.'); $body[] = pht( 'This may happen if there is a temporary network anomaly on the '. 'server side, like cosmic radiation or spooky ghosts. If this '. 'failure was caused by a transient service interruption, '. - 'Phabricator will recover momentarily.'); + 'this server will recover momentarily.'); $body[] = pht( 'This may also indicate that a more serious failure has occurred. '. - 'If this interruption does not resolve on its own, Phabricator '. + 'If this interruption does not resolve on its own, this server '. 'will soon detect the persistent disruption and degrade into '. 'read-only mode until the issue is resolved.'); $button = pht('Quite Unsettling'); @@ -70,13 +71,13 @@ case PhabricatorEnv::READONLY_SEVERED: $title = pht('Severed From Master'); $body[] = pht( - 'Phabricator has consistently been unable to reach the writable '. + 'This server has consistently been unable to reach the writable '. '("master") database while processing recent requests.'); $body[] = pht( 'This likely indicates a severe misconfiguration or major service '. 'interruption.'); $body[] = pht( - 'Phabricator will periodically retry the connection and recover '. + 'This server will periodically retry the connection and recover '. 'once service is restored. Most causes of persistent service '. 'interruption will require administrative intervention in order '. 'to restore service.'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsBlogController.php phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsBlogController.php --- phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsBlogController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsBlogController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,17 @@ +<?php + +final class PhabricatorRobotsBlogController + extends PhabricatorRobotsController { + + protected function newRobotsRules() { + $out = array(); + + // Allow everything on blog domains to be indexed. + + $out[] = 'User-Agent: *'; + $out[] = 'Crawl-delay: 1'; + + return $out; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsController.php phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsController.php --- phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,22 @@ +<?php + +abstract class PhabricatorRobotsController extends PhabricatorController { + + public function shouldRequireLogin() { + return false; + } + + final public function processRequest() { + $out = $this->newRobotsRules(); + + $content = implode("\n", $out)."\n"; + + return id(new AphrontPlainTextResponse()) + ->setContent($content) + ->setCacheDurationInSeconds(phutil_units('2 hours in seconds')) + ->setCanCDN(true); + } + + abstract protected function newRobotsRules(); + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsPlatformController.php phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsPlatformController.php --- phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsPlatformController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsPlatformController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,32 @@ +<?php + +final class PhabricatorRobotsPlatformController + extends PhabricatorRobotsController { + + protected function newRobotsRules() { + $out = array(); + + // Prevent indexing of '/diffusion/', since the content is not generally + // useful to index, web spiders get stuck scraping the history of every + // file, and much of the content is Ajaxed in anyway so spiders won't even + // see it. These pages are also relatively expensive to generate. + + // Note that this still allows commits (at '/rPxxxxx') to be indexed. + // They're probably not hugely useful, but suffer fewer of the problems + // Diffusion suffers and are hard to omit with 'robots.txt'. + + $out[] = 'User-Agent: *'; + $out[] = 'Disallow: /diffusion/'; + $out[] = 'Disallow: /source/'; + + // Add a small crawl delay (number of seconds between requests) for spiders + // which respect it. The intent here is to prevent spiders from affecting + // performance for users. The possible cost is slower indexing, but that + // seems like a reasonable tradeoff, since most Phabricator installs are + // probably not hugely concerned about cutting-edge SEO. + $out[] = 'Crawl-delay: 1'; + + return $out; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsResourceController.php phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsResourceController.php --- phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsResourceController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsResourceController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,18 @@ +<?php + +final class PhabricatorRobotsResourceController + extends PhabricatorRobotsController { + + protected function newRobotsRules() { + $out = array(); + + // See T13636. Prevent indexing of any content on resource domains. + + $out[] = 'User-Agent: *'; + $out[] = 'Disallow: /'; + $out[] = 'Crawl-delay: 1'; + + return $out; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsShortController.php phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsShortController.php --- phabricator-0~git20200925/phabricator/src/applications/system/controller/robots/PhabricatorRobotsShortController.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/controller/robots/PhabricatorRobotsShortController.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,18 @@ +<?php + +final class PhabricatorRobotsShortController + extends PhabricatorRobotsController { + + protected function newRobotsRules() { + $out = array(); + + // See T13636. Prevent indexing of any content on short domains. + + $out[] = 'User-Agent: *'; + $out[] = 'Disallow: /'; + $out[] = 'Crawl-delay: 1'; + + return $out; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/events/PhabricatorSystemDebugUIEventListener.php phabricator-0~git20220903/phabricator/src/applications/system/events/PhabricatorSystemDebugUIEventListener.php --- phabricator-0~git20200925/phabricator/src/applications/system/events/PhabricatorSystemDebugUIEventListener.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/events/PhabricatorSystemDebugUIEventListener.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,7 +42,17 @@ $submenu[] = id(new PhabricatorActionView()) ->setIcon('fa-address-card-o') ->setName(pht('View Hovercard')) - ->setHref(urisprintf('/search/hovercard/?phids[]=%s', $phid)); + ->setHref(urisprintf('/search/hovercard/?names=%s', $phid)); + + if ($object instanceof DifferentialRevision) { + $submenu[] = id(new PhabricatorActionView()) + ->setIcon('fa-database') + ->setName(pht('View Affected Path Index')) + ->setHref( + urisprintf( + '/differential/revision/paths/%s/', + $object->getID())); + } $developer_action = id(new PhabricatorActionView()) ->setName(pht('Advanced/Developer...')) diff -Nru phabricator-0~git20200925/phabricator/src/applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php phabricator-0~git20220903/phabricator/src/applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php --- phabricator-0~git20200925/phabricator/src/applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -109,9 +109,8 @@ 'projects and users.'. "\n\n". 'These tattered edges are an expected consequence of destroying '. - 'objects, and the Phabricator upstream will not help you fix '. - 'them. We strongly recommend disabling or archiving objects '. - 'instead.'))); + 'objects, and the upstream will not help you fix them. We '. + 'strongly recommend disabling or archiving objects instead.'))); $phids = mpull($named_objects, 'getPHID'); $handles = PhabricatorUser::getOmnipotentUser()->loadHandles($phids); diff -Nru phabricator-0~git20200925/phabricator/src/applications/tokens/query/PhabricatorTokenGivenQuery.php phabricator-0~git20220903/phabricator/src/applications/tokens/query/PhabricatorTokenGivenQuery.php --- phabricator-0~git20200925/phabricator/src/applications/tokens/query/PhabricatorTokenGivenQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/tokens/query/PhabricatorTokenGivenQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -26,10 +26,6 @@ return new PhabricatorTokenGiven(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,14 +8,16 @@ } public function getMethodDescription() { - return pht('Read transactions and comments for an object.'); + return pht( + 'Read transactions and comments for a particular object '. + 'or an entire object type.'); } - public function getMethodDocumentation() { + protected function newDocumentationPages(PhabricatorUser $viewer) { $markup = pht(<<<EOREMARKUP -When an object (like a task) is edited, Phabricator creates a "transaction" -and applies it. This list of transactions on each object is the basis for -essentially all edits and comments in Phabricator. Reviewing the transaction +When an object (like a task) is edited, the relevant application creates a +"transaction" and applies it. This list of transactions on each object is the +basis for essentially all edits and comments. Reviewing the transaction record allows you to see who edited an object, when, and how their edit changed things. @@ -23,6 +25,26 @@ just received a notification that an object has changed. See the Webhooks documentation for more detailed discussion of this use case. +One Object Type at a Time +========================= + +This API method can query transactions for any type of object which supports +transactions, but only one type of object can be queried per call. For example: +you can retrieve transactions affecting Tasks, or you can retrieve transactions +affecting Revisions, but a single call can not retrieve both. + +This is a technical limitation arising because (among other reasons) there is +no global ordering on transactions. + +To find transactions for a specific object (like a particular task), pass the +object PHID or an appropriate object identifier (like `T123`) as an +`objectIdentifier`. + +To find all transactions for an object type, pass the object type constant as +an `objectType`. For example, the correct identifier for tasks is `TASK`. (You +can quickly find an unknown type constant by looking at the PHID of an object +of that type.) + Constraints =========== @@ -55,17 +77,17 @@ $markup = $this->newRemarkupDocumentationView($markup); - return id(new PHUIObjectBoxView()) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setHeaderText(pht('Method Details')) - ->appendChild($markup); + return array( + $this->newDocumentationBoxPage($viewer, pht('Method Details'), $markup) + ->setAnchor('details'), + ); } protected function defineParamTypes() { return array( - 'objectIdentifier' => 'phid|string', - 'constraints' => 'map<string, wild>', + 'objectIdentifier' => 'optional phid|string', + 'objectType' => 'optional string', + 'constraints' => 'optional map<string, wild>', ) + $this->getPagerParamTypes(); } @@ -81,43 +103,19 @@ $viewer = $request->getUser(); $pager = $this->newPager($request); - $object_name = $request->getValue('objectIdentifier', null); - if (!strlen($object_name)) { - throw new Exception( - pht( - 'When calling "transaction.search", you must provide an object to '. - 'retrieve transactions for.')); - } - - $object = id(new PhabricatorObjectQuery()) - ->setViewer($viewer) - ->withNames(array($object_name)) - ->executeOne(); - if (!$object) { - throw new Exception( - pht( - 'No object "%s" exists.', - $object_name)); - } - - if (!($object instanceof PhabricatorApplicationTransactionInterface)) { - throw new Exception( - pht( - 'Object "%s" (of type "%s") does not implement "%s", so '. - 'transactions can not be loaded for it.', - $object_name, - get_class($object), - 'PhabricatorApplicationTransactionInterface')); - } + $object = $this->loadTemplateObject($request); $xaction_query = PhabricatorApplicationTransactionQuery::newQueryForObject( $object); $xaction_query ->needHandles(false) - ->withObjectPHIDs(array($object->getPHID())) ->setViewer($viewer); + if ($object->getPHID()) { + $xaction_query->withObjectPHIDs(array($object->getPHID())); + } + $constraints = $request->getValue('constraints', array()); $xaction_query = $this->applyConstraints($constraints, $xaction_query); @@ -355,4 +353,65 @@ ); } + private function loadTemplateObject(ConduitAPIRequest $request) { + $viewer = $request->getUser(); + + $object_identifier = $request->getValue('objectIdentifier'); + $object_type = $request->getValue('objectType'); + + $has_identifier = ($object_identifier !== null); + $has_type = ($object_type !== null); + + if (!$has_type && !$has_identifier) { + throw new Exception( + pht( + 'Calls to "transaction.search" must specify either an "objectType" '. + 'or an "objectIdentifier"')); + } else if ($has_type && $has_identifier) { + throw new Exception( + pht( + 'Calls to "transaction.search" must not specify both an '. + '"objectType" and an "objectIdentifier".')); + } + + if ($has_type) { + $all_types = PhabricatorPHIDType::getAllTypes(); + + if (!isset($all_types[$object_type])) { + ksort($all_types); + throw new Exception( + pht( + 'In call to "transaction.search", specified "objectType" ("%s") '. + 'is unknown. Valid object types are: %s.', + $object_type, + implode(', ', array_keys($all_types)))); + } + + $object = $all_types[$object_type]->newObject(); + } else { + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withNames(array($object_identifier)) + ->executeOne(); + if (!$object) { + throw new Exception( + pht( + 'In call to "transaction.search", specified "objectIdentifier" '. + '("%s") does not exist.', + $object_identifier)); + } + } + + if (!($object instanceof PhabricatorApplicationTransactionInterface)) { + throw new Exception( + pht( + 'In call to "transaction.search", selected object (of type "%s") '. + 'does not implement "%s", so transactions can not be loaded for it.', + get_class($object), + 'PhabricatorApplicationTransactionInterface')); + } + + return $object; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/constants/PhabricatorTransactions.php phabricator-0~git20220903/phabricator/src/applications/transactions/constants/PhabricatorTransactions.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/constants/PhabricatorTransactions.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/constants/PhabricatorTransactions.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,6 +7,7 @@ const TYPE_VIEW_POLICY = 'core:view-policy'; const TYPE_EDIT_POLICY = 'core:edit-policy'; const TYPE_JOIN_POLICY = 'core:join-policy'; + const TYPE_INTERACT_POLICY = 'core:interact-policy'; const TYPE_EDGE = 'core:edge'; const TYPE_CUSTOMFIELD = 'core:customfield'; const TYPE_TOKEN = 'token:give'; @@ -17,6 +18,7 @@ const TYPE_SUBTYPE = 'core:subtype'; const TYPE_HISTORY = 'core:history'; const TYPE_MFA = 'core:mfa'; + const TYPE_FILE = 'core:file'; const COLOR_RED = 'red'; const COLOR_ORANGE = 'orange'; diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/data/PhabricatorTransactionChange.php phabricator-0~git20220903/phabricator/src/applications/transactions/data/PhabricatorTransactionChange.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/data/PhabricatorTransactionChange.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/data/PhabricatorTransactionChange.php 2022-06-14 16:29:55.000000000 +0000 @@ -3,6 +3,7 @@ abstract class PhabricatorTransactionChange extends Phobject { private $transaction; + private $metadata = array(); private $oldValue; private $newValue; @@ -34,4 +35,13 @@ return $this->newValue; } + final public function setMetadata(array $metadata) { + $this->metadata = $metadata; + return $this; + } + + final public function getMetadata() { + return $this->metadata; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/edges/PhabricatorObjectHasFileEdgeType.php phabricator-0~git20220903/phabricator/src/applications/transactions/edges/PhabricatorObjectHasFileEdgeType.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/edges/PhabricatorObjectHasFileEdgeType.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/edges/PhabricatorObjectHasFileEdgeType.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -<?php - -final class PhabricatorObjectHasFileEdgeType extends PhabricatorEdgeType { - - const EDGECONST = 25; - - public function getInverseEdgeConstant() { - return PhabricatorFileHasObjectEdgeType::EDGECONST; - } - - public function shouldWriteInverseTransactions() { - return true; - } - - public function getTransactionAddString( - $actor, - $add_count, - $add_edges) { - - return pht( - '%s added %s file(s): %s.', - $actor, - $add_count, - $add_edges); - } - - public function getTransactionRemoveString( - $actor, - $rem_count, - $rem_edges) { - - return pht( - '%s removed %s file(s): %s.', - $actor, - $rem_count, - $rem_edges); - } - - public function getTransactionEditString( - $actor, - $total_count, - $add_count, - $add_edges, - $rem_count, - $rem_edges) { - - return pht( - '%s edited file(s), added %s: %s; removed %s: %s.', - $actor, - $add_count, - $add_edges, - $rem_count, - $rem_edges); - } - - public function getFeedAddString( - $actor, - $object, - $add_count, - $add_edges) { - - return pht( - '%s added %s file(s) for %s: %s.', - $actor, - $add_count, - $object, - $add_edges); - } - - public function getFeedRemoveString( - $actor, - $object, - $rem_count, - $rem_edges) { - - return pht( - '%s removed %s file(s) for %s: %s.', - $actor, - $rem_count, - $object, - $rem_edges); - } - - public function getFeedEditString( - $actor, - $object, - $total_count, - $add_count, - $add_edges, - $rem_count, - $rem_edges) { - - return pht( - '%s edited file(s) for %s, added %s: %s; removed %s: %s.', - $actor, - $object, - $add_count, - $add_edges, - $rem_count, - $rem_edges); - } - -} diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php phabricator-0~git20220903/phabricator/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,9 +38,7 @@ PhabricatorEnv::getDoclink('Conduit API: Using Edit Endpoints')); } - final public function getMethodDocumentation() { - $viewer = $this->getViewer(); - + final protected function newDocumentationPages(PhabricatorUser $viewer) { $engine = $this->newEditEngine() ->setViewer($viewer); @@ -48,16 +46,15 @@ $out = array(); - $out[] = $this->buildEditTypesBoxes($engine, $types); - - return $out; + return $this->buildEditTypesDocumentationPages($viewer, $engine, $types); } - private function buildEditTypesBoxes( + private function buildEditTypesDocumentationPages( + PhabricatorUser $viewer, PhabricatorEditEngine $engine, array $types) { - $boxes = array(); + $pages = array(); $summary_info = pht( 'This endpoint supports these types of transactions. See below for '. @@ -83,12 +80,14 @@ 'wide', )); - $boxes[] = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Transaction Types')) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->buildRemarkup($summary_info)) - ->appendChild($summary_table); + $title = pht('Transaction Summary'); + $content = array( + $this->buildRemarkup($summary_info), + $summary_table, + ); + + $pages[] = $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor('types'); foreach ($types as $type) { $section = array(); @@ -130,15 +129,18 @@ 'wide', )); - $boxes[] = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Transaction Type: %s', $type->getEditType())) - ->setCollapsed(true) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->appendChild($this->buildRemarkup($section)) - ->appendChild($type_table); + $title = $type->getEditType(); + $content = array( + $this->buildRemarkup($section), + $type_table, + ); + + $pages[] = $this->newDocumentationBoxPage($viewer, $title, $content) + ->setAnchor($type->getEditType()) + ->setIconIcon('fa-pencil'); } - return $boxes; + return $pages; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/editengine/PhabricatorEditEngine.php phabricator-0~git20220903/phabricator/src/applications/transactions/editengine/PhabricatorEditEngine.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/editengine/PhabricatorEditEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/editengine/PhabricatorEditEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -474,7 +474,9 @@ ->setIsDefault(true) ->setIsEdit(true); - if (!strlen($first->getName())) { + $first_name = $first->getName(); + + if ($first_name === null || $first_name === '') { $first->setName($this->getObjectCreateShortText()); } } else { @@ -1906,6 +1908,11 @@ $comment_text = $request->getStr('comment'); + $comment_metadata = $request->getStr('comment_metadata'); + if (strlen($comment_metadata)) { + $comment_metadata = phutil_json_decode($comment_metadata); + } + $actions = $request->getStr('editengine.actions'); if ($actions) { $actions = phutil_json_decode($actions); @@ -1921,10 +1928,9 @@ $viewer->getPHID(), $current_version); - $is_empty = (!strlen($comment_text) && !$actions); - $draft ->setProperty('comment', $comment_text) + ->setProperty('metadata', $comment_metadata) ->setProperty('actions', $actions) ->save(); @@ -2006,6 +2012,7 @@ if (strlen($comment_text) || !$xactions) { $xactions[] = id(clone $template) ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) + ->setMetadataValue('remarkup.control', $comment_metadata) ->attachComment( id(clone $comment_template) ->setContent($comment_text)); diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/editfield/PhabricatorRemarkupEditField.php phabricator-0~git20220903/phabricator/src/applications/transactions/editfield/PhabricatorRemarkupEditField.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/editfield/PhabricatorRemarkupEditField.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/editfield/PhabricatorRemarkupEditField.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,6 +7,10 @@ return new PhabricatorRemarkupControl(); } + protected function newHTTPParameterType() { + return new AphrontRemarkupHTTPParameterType(); + } + protected function newConduitParameterType() { return new ConduitStringParameterType(); } @@ -15,4 +19,55 @@ return new BulkRemarkupParameterType(); } + public function getValueForTransaction() { + $value = $this->getValue(); + + if ($value instanceof RemarkupValue) { + $value = $value->getCorpus(); + } + + return $value; + } + + public function getValueForDefaults() { + $value = parent::getValueForDefaults(); + + if ($value instanceof RemarkupValue) { + $value = $value->getCorpus(); + } + + return $value; + } + + protected function getDefaultValueFromConfiguration($value) { + + // See T13685. After changes to file attachment handling, the database + // was briefly poisoned with "array()" values as defaults. + + try { + $value = phutil_string_cast($value); + } catch (Exception $ex) { + $value = ''; + } catch (Throwable $ex) { + $value = ''; + } + + return $value; + } + + public function getMetadata() { + $defaults = array(); + + $value = $this->getValue(); + if ($value instanceof RemarkupValue) { + $defaults['remarkup.control'] = $value->getMetadata(); + } + + $metadata = parent::getMetadata(); + $metadata = $metadata + $defaults; + + return $metadata; + } + + } diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php phabricator-0~git20220903/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -78,12 +78,6 @@ $comment->setViewPolicy(PhabricatorPolicies::POLICY_PUBLIC); $comment->setEditPolicy($this->getActingAsPHID()); - $file_phids = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles( - $actor, - array( - $comment->getContent(), - )); - $xaction->openTransaction(); $xaction->beginReadLocking(); if ($xaction->getID()) { @@ -132,18 +126,6 @@ $xaction->endReadLocking(); $xaction->saveTransaction(); - // Add links to any files newly referenced by the edit. - if ($file_phids) { - $editor = new PhabricatorEdgeEditor(); - foreach ($file_phids as $file_phid) { - $editor->addEdge( - $xaction->getObjectPHID(), - PhabricatorObjectHasFileEdgeType::EDGECONST , - $file_phid); - } - $editor->save(); - } - return $this; } diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php phabricator-0~git20220903/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php 2022-06-14 16:29:55.000000000 +0000 @@ -226,7 +226,7 @@ public function getHeraldRuleMonograms() { // Convert the stored "<123>, <456>" string into a list: "H123", "H456". - $list = $this->heraldHeader; + $list = phutil_string_cast($this->heraldHeader); $list = preg_split('/[, ]+/', $list); foreach ($list as $key => $item) { @@ -332,6 +332,8 @@ $types[] = PhabricatorTransactions::TYPE_CREATE; $types[] = PhabricatorTransactions::TYPE_HISTORY; + $types[] = PhabricatorTransactions::TYPE_FILE; + if ($this->object instanceof PhabricatorEditEngineSubtypeInterface) { $types[] = PhabricatorTransactions::TYPE_SUBTYPE; } @@ -388,6 +390,101 @@ $new = $this->getTransactionNewValue($object, $xaction); $xaction->setNewValue($new); + + // Apply an optional transformation to convert "external" tranaction + // values (provided by APIs) into "internal" values. + + $old = $xaction->getOldValue(); + $new = $xaction->getNewValue(); + + $type = $xaction->getTransactionType(); + $xtype = $this->getModularTransactionType($object, $type); + if ($xtype) { + $xtype = clone $xtype; + $xtype->setStorage($xaction); + + + // TODO: Provide a modular hook for modern transactions to do a + // transformation. + list($old, $new) = array($old, $new); + + return; + } else { + switch ($type) { + case PhabricatorTransactions::TYPE_FILE: + list($old, $new) = $this->newFileTransactionInternalValues( + $object, + $xaction, + $old, + $new); + break; + } + } + + $xaction->setOldValue($old); + $xaction->setNewValue($new); + } + + private function newFileTransactionInternalValues( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction, + $old, + $new) { + + $old_map = array(); + + if (!$this->getIsNewObject()) { + $phid = $object->getPHID(); + + $attachment_table = new PhabricatorFileAttachment(); + $attachment_conn = $attachment_table->establishConnection('w'); + + $rows = queryfx_all( + $attachment_conn, + 'SELECT filePHID, attachmentMode FROM %R WHERE objectPHID = %s', + $attachment_table, + $phid); + $old_map = ipull($rows, 'attachmentMode', 'filePHID'); + } + + $mode_ref = PhabricatorFileAttachment::MODE_REFERENCE; + $mode_detach = PhabricatorFileAttachment::MODE_DETACH; + + $new_map = $old_map; + + foreach ($new as $file_phid => $attachment_mode) { + $is_ref = ($attachment_mode === $mode_ref); + $is_detach = ($attachment_mode === $mode_detach); + + if ($is_detach) { + unset($new_map[$file_phid]); + continue; + } + + $old_mode = idx($old_map, $file_phid); + + // If we're adding a reference to a file but it is already attached, + // don't touch it. + + if ($is_ref) { + if ($old_mode !== null) { + continue; + } + } + + $new_map[$file_phid] = $attachment_mode; + } + + foreach (array_keys($old_map + $new_map) as $key) { + if (isset($old_map[$key]) && isset($new_map[$key])) { + if ($old_map[$key] === $new_map[$key]) { + unset($old_map[$key]); + unset($new_map[$key]); + } + } + } + + return array($old_map, $new_map); } private function getTransactionOldValue( @@ -396,7 +493,7 @@ $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); @@ -428,6 +525,11 @@ return null; } return $object->getJoinPolicy(); + case PhabricatorTransactions::TYPE_INTERACT_POLICY: + if ($this->getIsNewObject()) { + return null; + } + return $object->getInteractPolicy(); case PhabricatorTransactions::TYPE_SPACE: if ($this->getIsNewObject()) { return null; @@ -476,6 +578,8 @@ return $xaction->getOldValue(); case PhabricatorTransactions::TYPE_COMMENT: return null; + case PhabricatorTransactions::TYPE_FILE: + return null; default: return $this->getCustomTransactionOldValue($object, $xaction); } @@ -487,7 +591,7 @@ $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); @@ -502,10 +606,12 @@ case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: case PhabricatorTransactions::TYPE_TOKEN: case PhabricatorTransactions::TYPE_INLINESTATE: case PhabricatorTransactions::TYPE_SUBTYPE: case PhabricatorTransactions::TYPE_HISTORY: + case PhabricatorTransactions::TYPE_FILE: return $xaction->getNewValue(); case PhabricatorTransactions::TYPE_MFA: return true; @@ -606,7 +712,7 @@ } $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { return $xtype->getTransactionHasEffect( $object, @@ -639,7 +745,7 @@ $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); @@ -658,11 +764,13 @@ case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: case PhabricatorTransactions::TYPE_SUBSCRIBERS: case PhabricatorTransactions::TYPE_INLINESTATE: case PhabricatorTransactions::TYPE_EDGE: case PhabricatorTransactions::TYPE_SPACE: case PhabricatorTransactions::TYPE_COMMENT: + case PhabricatorTransactions::TYPE_FILE: return $this->applyBuiltinInternalTransaction($object, $xaction); } @@ -675,7 +783,7 @@ $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); @@ -722,9 +830,11 @@ case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: case PhabricatorTransactions::TYPE_INLINESTATE: case PhabricatorTransactions::TYPE_SPACE: case PhabricatorTransactions::TYPE_COMMENT: + case PhabricatorTransactions::TYPE_FILE: return $this->applyBuiltinExternalTransaction($object, $xaction); } @@ -776,6 +886,9 @@ case PhabricatorTransactions::TYPE_JOIN_POLICY: $object->setJoinPolicy($xaction->getNewValue()); break; + case PhabricatorTransactions::TYPE_INTERACT_POLICY: + $object->setInteractPolicy($xaction->getNewValue()); + break; case PhabricatorTransactions::TYPE_SPACE: $object->setSpacePHID($xaction->getNewValue()); break; @@ -846,6 +959,81 @@ case PhabricatorTransactions::TYPE_HISTORY: $this->sendHistory = true; break; + case PhabricatorTransactions::TYPE_FILE: + $this->applyFileTransaction($object, $xaction); + break; + } + } + + private function applyFileTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + $old_map = $xaction->getOldValue(); + $new_map = $xaction->getNewValue(); + + $add_phids = array(); + $rem_phids = array(); + + foreach ($new_map as $phid => $mode) { + $add_phids[$phid] = $mode; + } + + foreach ($old_map as $phid => $mode) { + if (!isset($new_map[$phid])) { + $rem_phids[] = $phid; + } + } + + $now = PhabricatorTime::getNow(); + $object_phid = $object->getPHID(); + $attacher_phid = $this->getActingAsPHID(); + + $attachment_table = new PhabricatorFileAttachment(); + $attachment_conn = $attachment_table->establishConnection('w'); + + $add_sql = array(); + foreach ($add_phids as $add_phid => $add_mode) { + $add_sql[] = qsprintf( + $attachment_conn, + '(%s, %s, %s, %ns, %d, %d)', + $object_phid, + $add_phid, + $add_mode, + $attacher_phid, + $now, + $now); + } + + $rem_sql = array(); + foreach ($rem_phids as $rem_phid) { + $rem_sql[] = qsprintf( + $attachment_conn, + '%s', + $rem_phid); + } + + foreach (PhabricatorLiskDAO::chunkSQL($add_sql) as $chunk) { + queryfx( + $attachment_conn, + 'INSERT INTO %R (objectPHID, filePHID, attachmentMode, + attacherPHID, dateCreated, dateModified) + VALUES %LQ + ON DUPLICATE KEY UPDATE + attachmentMode = VALUES(attachmentMode), + attacherPHID = VALUES(attacherPHID), + dateModified = VALUES(dateModified)', + $attachment_table, + $chunk); + } + + foreach (PhabricatorLiskDAO::chunkSQL($rem_sql) as $chunk) { + queryfx( + $attachment_conn, + 'DELETE FROM %R WHERE objectPHID = %s AND filePHID in (%LQ)', + $attachment_table, + $object_phid, + $chunk); } } @@ -932,7 +1120,7 @@ continue; } - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if (!$xtype) { continue; } @@ -1129,7 +1317,6 @@ } $xactions = $this->sortTransactions($xactions); - $file_phids = $this->extractFilePHIDs($object, $xactions); if ($is_preview) { $this->loadHandles($xactions); @@ -1218,10 +1405,6 @@ } } - if ($file_phids) { - $this->attachFiles($object, $file_phids); - } - foreach ($xactions as $xaction) { $this->applyExternalEffects($object, $xaction); } @@ -1389,7 +1572,7 @@ return $xactions; } - final private function queuePublishing() { + private function queuePublishing() { $object = $this->publishableObject; $xactions = $this->publishableTransactions; @@ -1678,7 +1861,7 @@ foreach ($xactions as $xaction) { $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if (!$xtype) { $capabilities = $this->getLegacyRequiredCapabilities($xaction); } else { @@ -1779,6 +1962,8 @@ // Signing a transaction group with MFA does not require permissions // on its own. return null; + case PhabricatorTransactions::TYPE_FILE: + return null; case PhabricatorTransactions::TYPE_EDGE: return $this->getLegacyRequiredEdgeCapabilities($xaction); default: @@ -1951,11 +2136,11 @@ PhabricatorApplicationTransaction $u, PhabricatorApplicationTransaction $v) { + $object = $this->object; $type = $u->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { - $object = $this->object; return $xtype->mergeTransactions($object, $u, $v); } @@ -2055,9 +2240,94 @@ $xactions[] = $xaction; } + $file_xaction = $this->newFileTransaction( + $object, + $xactions, + $changes); + if ($file_xaction) { + $xactions[] = $file_xaction; + } + return $xactions; } + + private function newFileTransaction( + PhabricatorLiskDAO $object, + array $xactions, + array $remarkup_changes) { + + assert_instances_of( + $remarkup_changes, + 'PhabricatorTransactionRemarkupChange'); + + $new_map = array(); + + $viewer = $this->getActor(); + + $old_blocks = mpull($remarkup_changes, 'getOldValue'); + foreach ($old_blocks as $key => $old_block) { + $old_blocks[$key] = phutil_string_cast($old_block); + } + + $new_blocks = mpull($remarkup_changes, 'getNewValue'); + foreach ($new_blocks as $key => $new_block) { + $new_blocks[$key] = phutil_string_cast($new_block); + } + + $old_refs = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles( + $viewer, + $old_blocks); + $old_refs = array_fuse($old_refs); + + $new_refs = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles( + $viewer, + $new_blocks); + $new_refs = array_fuse($new_refs); + + $add_refs = array_diff_key($new_refs, $old_refs); + foreach ($add_refs as $file_phid) { + $new_map[$file_phid] = PhabricatorFileAttachment::MODE_REFERENCE; + } + + foreach ($remarkup_changes as $remarkup_change) { + $metadata = $remarkup_change->getMetadata(); + + $attached_phids = idx($metadata, 'attachedFilePHIDs', array()); + foreach ($attached_phids as $file_phid) { + + // If the blocks don't include a new embedded reference to this file, + // do not actually attach it. A common way for this to happen is for + // a user to upload a file, then change their mind and remove the + // reference. We do not want to attach the file if they decided against + // referencing it. + + if (!isset($new_map[$file_phid])) { + continue; + } + + $new_map[$file_phid] = PhabricatorFileAttachment::MODE_ATTACH; + } + } + + $file_phids = $this->extractFilePHIDs($object, $xactions); + foreach ($file_phids as $file_phid) { + $new_map[$file_phid] = PhabricatorFileAttachment::MODE_ATTACH; + } + + if (!$new_map) { + return null; + } + + $xaction = $object->getApplicationTransactionTemplate() + ->setTransactionType(PhabricatorTransactions::TYPE_FILE) + ->setMetadataValue('attach.implicit', true) + ->setNewValue($new_map); + + return $xaction; + } + + private function getRemarkupChanges(array $xactions) { $changes = array(); @@ -2596,7 +2866,7 @@ $errors = array(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $errors[] = $xtype->validateTransactions($object, $xactions); } @@ -2656,11 +2926,113 @@ idx($groups, $field->getFieldKey(), array())); } break; + case PhabricatorTransactions::TYPE_FILE: + $errors[] = $this->validateFileTransactions( + $object, + $xactions, + $type); + break; } return array_mergev($errors); } + private function validateFileTransactions( + PhabricatorLiskDAO $object, + array $xactions, + $transaction_type) { + + $errors = array(); + + $mode_map = PhabricatorFileAttachment::getModeList(); + $mode_map = array_fuse($mode_map); + + $file_phids = array(); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + + if (!is_array($new)) { + $errors[] = new PhabricatorApplicationTransactionValidationError( + $transaction_type, + pht('Invalid'), + pht( + 'File attachment transaction must have a map of files to '. + 'attachment modes, found "%s".', + phutil_describe_type($new)), + $xaction); + continue; + } + + foreach ($new as $file_phid => $attachment_mode) { + $file_phids[$file_phid] = $file_phid; + + if (is_string($attachment_mode) && isset($mode_map[$attachment_mode])) { + continue; + } + + if (!is_string($attachment_mode)) { + $errors[] = new PhabricatorApplicationTransactionValidationError( + $transaction_type, + pht('Invalid'), + pht( + 'File attachment mode (for file "%s") is invalid. Expected '. + 'a string, found "%s".', + $file_phid, + phutil_describe_type($attachment_mode)), + $xaction); + } else { + $errors[] = new PhabricatorApplicationTransactionValidationError( + $transaction_type, + pht('Invalid'), + pht( + 'File attachment mode "%s" (for file "%s") is invalid. Valid '. + 'modes are: %s.', + $attachment_mode, + $file_phid, + pht_list($mode_map)), + $xaction); + } + } + } + + if ($file_phids) { + $file_map = id(new PhabricatorFileQuery()) + ->setViewer($this->getActor()) + ->withPHIDs($file_phids) + ->execute(); + $file_map = mpull($file_map, null, 'getPHID'); + } else { + $file_map = array(); + } + + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + + if (!is_array($new)) { + continue; + } + + foreach ($new as $file_phid => $attachment_mode) { + if (isset($file_map[$file_phid])) { + continue; + } + + $errors[] = new PhabricatorApplicationTransactionValidationError( + $transaction_type, + pht('Invalid'), + pht( + 'File "%s" is invalid: it could not be loaded, or you do not '. + 'have permission to view it. You must be able to see a file to '. + 'attach it to an object.', + $file_phid), + $xaction); + } + } + + return $errors; + } + + public function validatePolicyTransaction( PhabricatorLiskDAO $object, array $xactions, @@ -2909,7 +3281,7 @@ * @return bool True if the field will be an empty text field after edits. */ protected function validateIsEmptyTextField($field_value, array $xactions) { - if (strlen($field_value) && empty($xactions)) { + if (($field_value !== null && strlen($field_value)) && empty($xactions)) { return false; } @@ -3637,8 +4009,9 @@ private function getMailDiffSectionHeader($xaction) { $type = $xaction->getTransactionType(); + $object = $this->object; - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { return $xtype->getMailDiffSectionHeader(); } @@ -4031,20 +4404,12 @@ PhabricatorLiskDAO $object, array $xactions) { - $changes = $this->getRemarkupChanges($xactions); - $blocks = mpull($changes, 'getNewValue'); - $phids = array(); - if ($blocks) { - $phids[] = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles( - $this->getActor(), - $blocks); - } foreach ($xactions as $xaction) { $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $phids[] = $xtype->extractFilePHIDs($object, $xaction->getNewValue()); } else { @@ -4055,20 +4420,8 @@ } $phids = array_unique(array_filter(array_mergev($phids))); - if (!$phids) { - return array(); - } - - // Only let a user attach files they can actually see, since this would - // otherwise let you access any file by attaching it to an object you have - // view permission on. - $files = id(new PhabricatorFileQuery()) - ->setViewer($this->getActor()) - ->withPHIDs($phids) - ->execute(); - - return mpull($files, 'getPHID'); + return $phids; } /** @@ -4081,28 +4434,6 @@ } - /** - * @task files - */ - private function attachFiles( - PhabricatorLiskDAO $object, - array $file_phids) { - - if (!$file_phids) { - return; - } - - $editor = new PhabricatorEdgeEditor(); - - $src = $object->getPHID(); - $type = PhabricatorObjectHasFileEdgeType::EDGECONST; - foreach ($file_phids as $dst) { - $editor->addEdge($src, $type, $dst); - } - - $editor->save(); - } - private function applyInverseEdgeTransactions( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction, @@ -4207,7 +4538,7 @@ * @return dict<string, wild> Serializable editor state. * @task workers */ - final private function getWorkerState() { + private function getWorkerState() { $state = array(); foreach ($this->getAutomaticStateProperties() as $property) { $state[$property] = $this->$property; @@ -4336,7 +4667,7 @@ * @return map<string, wild> Map of encoded values. * @task workers */ - final private function encodeStateForStorage( + private function encodeStateForStorage( array $state, array $encodings) { @@ -4382,7 +4713,7 @@ * @return map<string, wild> Map of decoded values. * @task workers */ - final private function decodeStateFromStorage( + private function decodeStateFromStorage( array $state, array $encodings) { @@ -4549,20 +4880,11 @@ } } - $phid = $object->getPHID(); - - $attached_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( - $phid, - PhabricatorObjectHasFileEdgeType::EDGECONST); - if (!$attached_phids) { - return; - } - $omnipotent_viewer = PhabricatorUser::getOmnipotentUser(); $files = id(new PhabricatorFileQuery()) ->setViewer($omnipotent_viewer) - ->withPHIDs($attached_phids) + ->withAttachedObjectPHIDs(array($object->getPHID())) ->execute(); foreach ($files as $file) { $view_policy = $file->getViewPolicy(); @@ -4633,9 +4955,11 @@ $proxy_phids); } - private function getModularTransactionTypes() { + private function getModularTransactionTypes( + PhabricatorLiskDAO $object) { + if ($this->modularTypes === null) { - $template = $this->object->getApplicationTransactionTemplate(); + $template = $object->getApplicationTransactionTemplate(); if ($template instanceof PhabricatorModularTransaction) { $xtypes = $template->newModularTransactionTypes(); foreach ($xtypes as $key => $xtype) { @@ -4653,8 +4977,8 @@ return $this->modularTypes; } - private function getModularTransactionType($type) { - $types = $this->getModularTransactionTypes(); + private function getModularTransactionType($object, $type) { + $types = $this->getModularTransactionTypes($object); return idx($types, $type); } @@ -5214,7 +5538,7 @@ foreach ($xactions as $xaction) { $type = $xaction->getTransactionType(); - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); @@ -5261,8 +5585,9 @@ private function getTitleForTextMail( PhabricatorApplicationTransaction $xaction) { $type = $xaction->getTransactionType(); + $object = $this->object; - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); @@ -5278,8 +5603,9 @@ private function getTitleForHTMLMail( PhabricatorApplicationTransaction $xaction) { $type = $xaction->getTransactionType(); + $object = $this->object; - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); @@ -5296,8 +5622,9 @@ private function getBodyForTextMail( PhabricatorApplicationTransaction $xaction) { $type = $xaction->getTransactionType(); + $object = $this->object; - $xtype = $this->getModularTransactionType($type); + $xtype = $this->getModularTransactionType($object, $type); if ($xtype) { $xtype = clone $xtype; $xtype->setStorage($xaction); diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/engine/PhabricatorTimelineEngine.php phabricator-0~git20220903/phabricator/src/applications/transactions/engine/PhabricatorTimelineEngine.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/engine/PhabricatorTimelineEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/engine/PhabricatorTimelineEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -84,6 +84,7 @@ return $view ->setViewer($viewer) + ->setObject($object) ->setObjectPHID($object->getPHID()) ->setTransactions($xactions); } diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php phabricator-0~git20220903/phabricator/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ public function supportsObject( PhabricatorEditEngine $engine, PhabricatorApplicationTransactionInterface $object) { - return $engine->supportsSubtypes(); + return ($object instanceof PhabricatorEditEngineSubtypeInterface); } public function buildCustomEditFields( diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php phabricator-0~git20220903/phabricator/src/applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -46,10 +46,6 @@ return $this->newApplicationTransactionCommentTemplate(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); $alias = $this->getPrimaryTableAlias(); diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/storage/PhabricatorApplicationTransaction.php phabricator-0~git20220903/phabricator/src/applications/transactions/storage/PhabricatorApplicationTransaction.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/storage/PhabricatorApplicationTransaction.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/storage/PhabricatorApplicationTransaction.php 2022-06-14 16:29:55.000000000 +0000 @@ -244,6 +244,18 @@ ->setNewValue($new_value); } + $metadata = $this->getMetadataValue('remarkup.control'); + + if (!is_array($metadata)) { + $metadata = array(); + } + + foreach ($changes as $change) { + if (!$change->getMetadata()) { + $change->setMetadata($metadata); + } + } + return $changes; } @@ -334,6 +346,9 @@ $phids[] = $old; $phids[] = $new; break; + case PhabricatorTransactions::TYPE_FILE: + $phids[] = array_keys($old + $new); + break; case PhabricatorTransactions::TYPE_EDGE: $record = PhabricatorEdgeChangeRecord::newFromTransaction($this); $phids[] = $record->getChangedPHIDs(); @@ -350,6 +365,7 @@ case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: if (!PhabricatorPolicyQuery::isSpecialPolicy($old)) { $phids[] = array($old); } @@ -408,7 +424,7 @@ public function renderHandleLink($phid) { if ($this->renderingTarget == self::TARGET_HTML) { - return $this->getHandle($phid)->renderLink(); + return $this->getHandle($phid)->renderHovercardLink(); } else { return $this->getHandle($phid)->getLinkName(); } @@ -479,6 +495,7 @@ case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: return 'fa-lock'; case PhabricatorTransactions::TYPE_EDGE: switch ($this->getMetadataValue('edge:type')) { @@ -581,6 +598,13 @@ return true; } + // Always hide file attach/detach transactions. + if ($xaction_type === PhabricatorTransactions::TYPE_FILE) { + if ($this->getMetadataValue('attach.implicit')) { + return true; + } + } + // Hide creation transactions if the old value is empty. These are // transactions like "alice set the task title to: ...", which are // essentially never interesting. @@ -590,6 +614,7 @@ case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: case PhabricatorTransactions::TYPE_SPACE: break; case PhabricatorTransactions::TYPE_SUBTYPE: @@ -602,7 +627,7 @@ } if (!is_array($old)) { - if (!strlen($old)) { + if ($old === '' || $old === null) { return true; } @@ -634,6 +659,7 @@ case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: case PhabricatorTransactions::TYPE_SPACE: if ($this->getIsCreateTransaction()) { break; @@ -707,7 +733,7 @@ switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_TOKEN: return true; - case PhabricatorTransactions::TYPE_EDGE: + case PhabricatorTransactions::TYPE_EDGE: $edge_type = $this->getMetadataValue('edge:type'); switch ($edge_type) { case PhabricatorObjectMentionsObjectEdgeType::EDGECONST: @@ -887,6 +913,10 @@ return pht( 'This %s already has that join policy.', $this->getApplicationObjectTypeName()); + case PhabricatorTransactions::TYPE_INTERACT_POLICY: + return pht( + 'This %s already has that interact policy.', + $this->getApplicationObjectTypeName()); case PhabricatorTransactions::TYPE_SUBSCRIBERS: return pht( 'All users are already subscribed to this %s.', @@ -964,6 +994,19 @@ $this->renderPolicyName($old, 'old'), $this->renderPolicyName($new, 'new')); } + case PhabricatorTransactions::TYPE_INTERACT_POLICY: + if ($this->getIsCreateTransaction()) { + return pht( + '%s created this object with interact policy "%s".', + $this->renderHandleLink($author_phid), + $this->renderPolicyName($new, 'new')); + } else { + return pht( + '%s changed the interact policy from "%s" to "%s".', + $this->renderHandleLink($author_phid), + $this->renderPolicyName($old, 'old'), + $this->renderPolicyName($new, 'new')); + } case PhabricatorTransactions::TYPE_SPACE: if ($this->getIsCreateTransaction()) { return pht( @@ -1009,6 +1052,124 @@ $this->renderHandleLink($author_phid)); } break; + case PhabricatorTransactions::TYPE_FILE: + $add = array_diff_key($new, $old); + $add = array_keys($add); + + $rem = array_diff_key($old, $new); + $rem = array_keys($rem); + + $mod = array(); + foreach ($old + $new as $key => $ignored) { + if (!isset($old[$key])) { + continue; + } + + if (!isset($new[$key])) { + continue; + } + + if ($old[$key] === $new[$key]) { + continue; + } + + $mod[] = $key; + } + + // Specialize the specific case of only modifying files and upgrading + // references to attachments. This is accessible via the UI and can + // be shown more clearly than the generic default transaction shows + // it. + + $mode_reference = PhabricatorFileAttachment::MODE_REFERENCE; + $mode_attach = PhabricatorFileAttachment::MODE_ATTACH; + + $is_refattach = false; + if ($mod && !$add && !$rem) { + $all_refattach = true; + foreach ($mod as $phid) { + if (idx($old, $phid) !== $mode_reference) { + $all_refattach = false; + break; + } + if (idx($new, $phid) !== $mode_attach) { + $all_refattach = false; + break; + } + } + $is_refattach = $all_refattach; + } + + if ($is_refattach) { + return pht( + '%s attached %s referenced file(s): %s.', + $this->renderHandleLink($author_phid), + phutil_count($mod), + $this->renderHandleList($mod)); + } else if ($add && $rem && $mod) { + return pht( + '%s updated %s attached file(s), added %s: %s; removed %s: %s; '. + 'modified %s: %s.', + $this->renderHandleLink($author_phid), + new PhutilNumber(count($add) + count($rem)), + phutil_count($add), + $this->renderHandleList($add), + phutil_count($rem), + $this->renderHandleList($rem), + phutil_count($mod), + $this->renderHandleList($mod)); + } else if ($add && $rem) { + return pht( + '%s updated %s attached file(s), added %s: %s; removed %s: %s.', + $this->renderHandleLink($author_phid), + new PhutilNumber(count($add) + count($rem)), + phutil_count($add), + $this->renderHandleList($add), + phutil_count($rem), + $this->renderHandleList($rem)); + } else if ($add && $mod) { + return pht( + '%s updated %s attached file(s), added %s: %s; modified %s: %s.', + $this->renderHandleLink($author_phid), + new PhutilNumber(count($add) + count($mod)), + phutil_count($add), + $this->renderHandleList($add), + phutil_count($mod), + $this->renderHandleList($mod)); + } else if ($rem && $mod) { + return pht( + '%s updated %s attached file(s), removed %s: %s; modified %s: %s.', + $this->renderHandleLink($author_phid), + new PhutilNumber(count($rem) + count($mod)), + phutil_count($rem), + $this->renderHandleList($rem), + phutil_count($mod), + $this->renderHandleList($mod)); + } else if ($add) { + return pht( + '%s attached %s file(s): %s.', + $this->renderHandleLink($author_phid), + phutil_count($add), + $this->renderHandleList($add)); + } else if ($rem) { + return pht( + '%s removed %s attached file(s): %s.', + $this->renderHandleLink($author_phid), + phutil_count($rem), + $this->renderHandleList($rem)); + } else if ($mod) { + return pht( + '%s modified %s attached file(s): %s.', + $this->renderHandleLink($author_phid), + phutil_count($mod), + $this->renderHandleList($mod)); + } else { + return pht( + '%s attached files...', + $this->renderHandleLink($author_phid)); + } + + break; case PhabricatorTransactions::TYPE_EDGE: $record = PhabricatorEdgeChangeRecord::newFromTransaction($this); $add = $record->getAddedPHIDs(); @@ -1204,6 +1365,11 @@ '%s changed the join policy for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); + case PhabricatorTransactions::TYPE_INTERACT_POLICY: + return pht( + '%s changed the interact policy for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); case PhabricatorTransactions::TYPE_SUBSCRIBERS: return pht( '%s updated subscribers of %s.', @@ -1426,6 +1592,7 @@ case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: + case PhabricatorTransactions::TYPE_INTERACT_POLICY: return pht('Changed Policy'); case PhabricatorTransactions::TYPE_SUBSCRIBERS: return pht('Changed Subscribers'); @@ -1440,6 +1607,8 @@ public function hasChangeDetails() { switch ($this->getTransactionType()) { + case PhabricatorTransactions::TYPE_FILE: + return true; case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { @@ -1455,6 +1624,11 @@ } public function renderChangeDetailsForMail(PhabricatorUser $viewer) { + switch ($this->getTransactionType()) { + case PhabricatorTransactions::TYPE_FILE: + return false; + } + $view = $this->renderChangeDetails($viewer); if ($view instanceof PhabricatorApplicationTransactionTextDiffDetailView) { return $view->renderForMail(); @@ -1464,6 +1638,8 @@ public function renderChangeDetails(PhabricatorUser $viewer) { switch ($this->getTransactionType()) { + case PhabricatorTransactions::TYPE_FILE: + return $this->newFileTransactionChangeDetails($viewer); case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { @@ -1730,6 +1906,66 @@ ->addInt(-$this->getActionStrength()); } + private function newFileTransactionChangeDetails(PhabricatorUser $viewer) { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $phids = array_keys($old + $new); + $handles = $viewer->loadHandles($phids); + + $names = array( + PhabricatorFileAttachment::MODE_REFERENCE => pht('Referenced'), + PhabricatorFileAttachment::MODE_ATTACH => pht('Attached'), + ); + + $rows = array(); + foreach ($old + $new as $phid => $ignored) { + $handle = $handles[$phid]; + + $old_mode = idx($old, $phid); + $new_mode = idx($new, $phid); + + if ($old_mode === null) { + $old_name = pht('None'); + } else if (isset($names[$old_mode])) { + $old_name = $names[$old_mode]; + } else { + $old_name = pht('Unknown ("%s")', $old_mode); + } + + if ($new_mode === null) { + $new_name = pht('Detached'); + } else if (isset($names[$new_mode])) { + $new_name = $names[$new_mode]; + } else { + $new_name = pht('Unknown ("%s")', $new_mode); + } + + $rows[] = array( + $handle->renderLink(), + $old_name, + $new_name, + ); + } + + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + pht('File'), + pht('Old Mode'), + pht('New Mode'), + )) + ->setColumnClasses( + array( + 'pri', + )); + + return id(new PHUIBoxView()) + ->addMargin(PHUI::MARGIN_SMALL) + ->appendChild($table); + } + + /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ @@ -1797,5 +2033,4 @@ $this->saveTransaction(); } - } diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php phabricator-0~git20220903/phabricator/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php 2022-06-14 16:29:55.000000000 +0000 @@ -185,7 +185,7 @@ $fields = $this->reorderFields($fields); $preamble = $this->getPreamble(); - if (strlen($preamble)) { + if ($preamble !== null && strlen($preamble)) { $fields = array( 'config.preamble' => id(new PhabricatorInstructionsEditField()) ->setKey('config.preamble') diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php phabricator-0~git20220903/phabricator/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php 2022-06-14 16:29:55.000000000 +0000 @@ -67,7 +67,7 @@ %s ``` -However, `your.install.com` will be the domain where your copy of Phabricator +However, `your.install.com` will be the domain where your copy of this software is installed, and `application/` will be the URI for an application. Some applications have multiple forms for creating objects or URIs that look a little different than this example, so the URI may not look exactly like this. diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php phabricator-0~git20220903/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php 2022-06-14 16:29:55.000000000 +0000 @@ -294,18 +294,43 @@ } private function renderCommentPanel() { + $viewer = $this->getViewer(); + + $remarkup_control = id(new PhabricatorRemarkupControl()) + ->setViewer($viewer) + ->setID($this->getCommentID()) + ->addClass('phui-comment-fullwidth-control') + ->addClass('phui-comment-textarea-control') + ->setCanPin(true) + ->setName('comment'); + $draft_comment = ''; + $draft_metadata = array(); $draft_key = null; - if ($this->getDraft()) { - $draft_comment = $this->getDraft()->getDraft(); - $draft_key = $this->getDraft()->getDraftKey(); + + $legacy_draft = $this->getDraft(); + if ($legacy_draft) { + $draft_comment = $legacy_draft->getDraft(); + $draft_key = $legacy_draft->getDraftKey(); } $versioned_draft = $this->getVersionedDraft(); if ($versioned_draft) { - $draft_comment = $versioned_draft->getProperty('comment', ''); + $draft_comment = $versioned_draft->getProperty( + 'comment', + $draft_comment); + $draft_metadata = $versioned_draft->getProperty( + 'metadata', + $draft_metadata); } + $remarkup_control->setValue($draft_comment); + + if (!is_array($draft_metadata)) { + $draft_metadata = array(); + } + $remarkup_control->setRemarkupMetadata($draft_metadata); + if (!$this->getObjectPHID()) { throw new PhutilInvalidStateException('setObjectPHID', 'render'); } @@ -314,7 +339,7 @@ $version_value = $this->getCurrentVersion(); $form = id(new AphrontFormView()) - ->setUser($this->getUser()) + ->setUser($viewer) ->addSigil('transaction-append') ->setWorkflow(true) ->setFullWidth($this->fullWidth) @@ -465,15 +490,7 @@ ->setValue($this->getSubmitButtonName()); $form - ->appendChild( - id(new PhabricatorRemarkupControl()) - ->setID($this->getCommentID()) - ->addClass('phui-comment-fullwidth-control') - ->addClass('phui-comment-textarea-control') - ->setCanPin(true) - ->setName('comment') - ->setUser($this->getUser()) - ->setValue($draft_comment)) + ->appendChild($remarkup_control) ->appendChild( id(new AphrontFormSubmitControl()) ->addClass('phui-comment-fullwidth-control') diff -Nru phabricator-0~git20200925/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php phabricator-0~git20220903/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php --- phabricator-0~git20200925/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/transactions/view/PhabricatorApplicationTransactionView.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,6 +9,7 @@ private $engine; private $showEditActions = true; private $isPreview; + private $object; private $objectPHID; private $shouldTerminate = false; private $quoteTargetID; @@ -41,6 +42,16 @@ return $this->quoteTargetID; } + public function setObject( + PhabricatorApplicationTransactionInterface $object) { + $this->object = $object; + return $this; + } + + private function getObject() { + return $this->object; + } + public function setObjectPHID($object_phid) { $this->objectPHID = $object_phid; return $this; @@ -238,6 +249,12 @@ $engine = id(new PhabricatorMarkupEngine()) ->setViewer($this->getViewer()); + + $object = $this->getObject(); + if ($object) { + $engine->setContextObject($object); + } + foreach ($this->transactions as $xaction) { if (!$xaction->hasComment()) { continue; diff -Nru phabricator-0~git20200925/phabricator/src/applications/uiexample/examples/PhabricatorProjectBuiltinsExample.php phabricator-0~git20220903/phabricator/src/applications/uiexample/examples/PhabricatorProjectBuiltinsExample.php --- phabricator-0~git20200925/phabricator/src/applications/uiexample/examples/PhabricatorProjectBuiltinsExample.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/uiexample/examples/PhabricatorProjectBuiltinsExample.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,7 +7,7 @@ } public function getDescription() { - return pht('Builtin Project Images that ship with Phabricator.'); + return pht('Builtin Project Images.'); } public function getCategory() { diff -Nru phabricator-0~git20200925/phabricator/src/applications/uiexample/examples/PHUIBadgeExample.php phabricator-0~git20220903/phabricator/src/applications/uiexample/examples/PHUIBadgeExample.php --- phabricator-0~git20200925/phabricator/src/applications/uiexample/examples/PHUIBadgeExample.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/uiexample/examples/PHUIBadgeExample.php 2022-06-14 16:29:55.000000000 +0000 @@ -19,7 +19,7 @@ $badges1 = array(); $badges1[] = id(new PHUIBadgeView()) ->setIcon('fa-users') - ->setHeader(pht('Phacility High Command')) + ->setHeader(pht('High Command')) ->setHref('/') ->setSource('Projects (automatic)') ->addByline(pht('Dec 31, 1969')) @@ -56,7 +56,7 @@ $badges2 = array(); $badges2[] = id(new PHUIBadgeView()) ->setIcon('fa-user') - ->setHeader(pht('Phabricator User')) + ->setHeader(pht('User')) ->setSubhead(pht('Confirmed your account.')) ->setQuality(PhabricatorBadgesQuality::POOR) ->setSource(pht('People (automatic)')) @@ -111,9 +111,9 @@ $badges2[] = id(new PHUIBadgeView()) ->setIcon('fa-compass') ->setHeader(pht('Lead Developer')) - ->setSubhead(pht('Lead Developer of Phabricator')) + ->setSubhead(pht('Lead Developer of Software')) ->setQuality(PhabricatorBadgesQuality::HEIRLOOM) - ->setSource(pht('Direct Award (epriestley)')) + ->setSource(pht('Direct Award')) ->addByline(pht('Dec 31, 1969')) ->addByline('1 Awarded (0.4%)'); diff -Nru phabricator-0~git20200925/phabricator/src/applications/uiexample/examples/PHUIHovercardUIExample.php phabricator-0~git20220903/phabricator/src/applications/uiexample/examples/PHUIHovercardUIExample.php --- phabricator-0~git20200925/phabricator/src/applications/uiexample/examples/PHUIHovercardUIExample.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/uiexample/examples/PHUIHovercardUIExample.php 2022-06-14 16:29:55.000000000 +0000 @@ -39,7 +39,7 @@ $task_handle = $this->createBasicDummyHandle( 'T123', ManiphestTaskPHIDType::TYPECONST, - pht('Improve Mobile Experience for Phabricator')); + pht('Improve Mobile Experience')); $tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_STATE) diff -Nru phabricator-0~git20200925/phabricator/src/applications/xhprof/query/PhabricatorXHProfSampleQuery.php phabricator-0~git20220903/phabricator/src/applications/xhprof/query/PhabricatorXHProfSampleQuery.php --- phabricator-0~git20200925/phabricator/src/applications/xhprof/query/PhabricatorXHProfSampleQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/applications/xhprof/query/PhabricatorXHProfSampleQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -20,10 +20,6 @@ return new PhabricatorXHProfSample(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); diff -Nru phabricator-0~git20200925/phabricator/src/docs/book/phabricator.book phabricator-0~git20220903/phabricator/src/docs/book/phabricator.book --- phabricator-0~git20200925/phabricator/src/docs/book/phabricator.book 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/book/phabricator.book 2022-06-14 16:29:55.000000000 +0000 @@ -244,10 +244,6 @@ "name": "PHPAST", "include": "(^src/applications/phpast/)" }, - "phragment": { - "name": "Phragment", - "include": "(^src/applications/phragment/)" - }, "phrequent": { "name": "Phrequent", "include": "(^src/applications/phrequent/)" @@ -272,10 +268,6 @@ "name": "Projects", "include": "(^src/applications/project/)" }, - "releeph": { - "name": "Releeph", - "include": "(^src/applications/releeph/)" - }, "remarkup": { "name": "Remarkup", "include": [ diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/adding_new_classes.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/adding_new_classes.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/adding_new_classes.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/adding_new_classes.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ @{class@phabricator:PhabricatorApplication}. It discovers available workflows in `arc` by looking at all of the subclasses of @{class@arcanist:ArcanistWorkflow}. It discovers available locales -by looking at all of the subclasses of @{class@libphutil:PhutilLocale}. +by looking at all of the subclasses of @{class@arcanist:PhutilLocale}. This pattern holds in many cases, so you can often add functionality by adding new classes with no other work. Phabricator will automatically discover and @@ -49,8 +49,8 @@ features, or get started on a larger project. Extending Phabricator like this imposes a small performance penalty compared to using a library. -This directory exists in all libphutil libraries, so you can find similar -directories in `arcanist/src/extensions/` and `libphutil/src/extensions/`. +This directory exists in all libphutil libraries, so you can find a similar +directory in `arcanist/src/extensions/`. For example, to add a new application, create a file like this one and add it to `phabricator/src/extensions/`. @@ -171,8 +171,8 @@ NOTE: If Phabricator isn't located next to your custom library, specify a path which actually points to the `phabricator/` directory. -You do not need to declare dependencies on `arcanist` or `libphutil`, -since `arc liberate` automatically loads them. +You do not need to declare dependencies on `arcanist`, since `arc liberate` +automatically loads them. Finally, edit your Phabricator config to tell it to load your library at runtime, by adding it to `load-libraries`: @@ -206,8 +206,8 @@ What You Can Extend And Invoke ============================== -libphutil, Arcanist and Phabricator are strict about extensibility of classes -and visibility of methods and properties. Most classes are marked `final`, and +Arcanist and Phabricator are strict about extensibility of classes and +visibility of methods and properties. Most classes are marked `final`, and methods have the minimum required visibility (protected or private). The goal of this strictness is to make it clear what you can safely extend, access, and invoke, so your code will keep working as the upstream changes. @@ -215,8 +215,8 @@ IMPORTANT: We'll still break APIs frequently. The upstream does not support extension development, and none of these APIs are stable. -When developing libraries to work with libphutil, Arcanist and Phabricator, you -should respect method and property visibility. +When developing libraries to work with Arcanist and Phabricator, you should +respect method and property visibility. If you want to add features but can't figure out how to do it without changing Phabricator code, here are some approaches you may be able to take: diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/bug_reports.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/bug_reports.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/bug_reports.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/bug_reports.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -1,173 +1,5 @@ @title Contributing Bug Reports @group detail -Describes how to file an effective Phabricator bug report. +Effective June 1, 2021: Phabricator is no longer actively maintained and no longer accepts bug reports. -Level Requirements -================== - -We accept bug reports through two channels: paid support and community -support. - -If you are a paying customer, use the -[[ https://admin.phacility.com/u/support | Support Channel ]] for your account -to report bugs. This document may help you file reports which we can resolve -more quickly, but you do not need to read it or follow the guidelines. - -Other users can follow the guidelines in this document to file bug reports on -the community forum. - - -Overview -======== - -This article describes how to file an effective Phabricator bug report. - -The most important things to do are: - - - check the list of common fixes below; - - make sure Phabricator is up to date; - - make sure we support your setup; - - gather debugging information; and - - explain how to reproduce the issue. - -The rest of this article walks through these points in detail. - -For general information on contributing to Phabricator, see -@{article:Contributor Introduction}. - - -Common Fixes -============ - -Before you file a report, here are some common solutions to problems: - - - **Update Phabricator**: We receive a lot of bug reports about issues we have - already fixed in HEAD. Updating often resolves issues. It is common for - issues to be fixed in less than 24 hours, so even if you've updated recently - you should update again. If you aren't sure how to update, see the next - section. - - **Update Libraries**: Make sure `libphutil/`, `arcanist/` and - `phabricator/` are all up to date. Users often update `phabricator/` but - forget to update `arcanist/` or `libphutil/`. When you update, make sure you - update all three libraries. - - **Restart Apache or PHP-FPM**: Phabricator uses caches which don't get - reset until you restart Apache or PHP-FPM. After updating, make sure you - restart. - - -Update Phabricator -================== - -Before filing a bug, make sure you are up to date. We receive many bug reports -for issues we have already fixed, and even if we haven't fixed an issue we'll -be able to resolve it more easily if you file a report based on HEAD. (For -example, an old stack trace may not have the right line numbers, which will -make it more difficult for us to figure out what's going wrong.) - -To update Phabricator, use a script like the one described in -@{article:Upgrading Phabricator}. - -**If you can not update** for some reason, please include the version of -Phabricator you are running when you file a report. - -For help, see @{article:Providing Version Information}. - - -Supported Issues -================ - -Before filing a bug, make sure you're filing an issue against something we -support. - -**We can NOT help you with issues we can not reproduce.** It is critical that -you explain how to reproduce the issue when filing a report. - -For help, see @{article:Providing Reproduction Steps}. - -**We do NOT support prototype applications.** If you're running into an issue -with a prototype application, you're on your own. For more information about -prototype applications, see @{article:User Guide: Prototype Applications}. - -**We do NOT support third-party packages or instructions.** If you installed -Phabricator (or configured some aspect of it) using a third-party package or by -following a third-party guide (like a blog post), we can not help you. -Phabricator changes quickly and third-party information is unreliable and often -falls out of date. Contact the maintainer of the package or guide you used, -or reinstall following the upstream instructions. - -**We do NOT support custom code development or third-party libraries.** If -you're writing an extension, you're on your own. We provide some documentation, -but can not help you with extension or library development. If you downloaded a -library from somewhere, contact the library maintainer. - -**We do NOT support bizarre environments.** If your issue is specific to an -unusual installation environment, we generally will not help you find a -workaround. Install Phabricator in a normal environment instead. Examples of -unusual environments are shared hosts, nontraditional hosts (gaming consoles, -storage appliances), and hosts with unusually tight resource constraints. The -vast majority of users run Phabricator in normal environments (modern computers -with root access) and these are the only environments we support. - -Otherwise, if you're having an issue with a supported first-party application -and followed the upstream install instructions on a normal computer, we're happy -to try to help. - - -Getting More Information -======================== - -For some issues, there are places you can check for more information. This may -help you resolve the issue yourself. Even if it doesn't, this information can -help us figure out and resolve an issue. - - - For issues with `arc` or any other command-line script, you can get more - details about what the script is doing by adding the `--trace` flag. - - For issues with Phabricator, check your webserver error logs. - - For Apache, this is often `/var/log/httpd/error.log`, or - `/var/log/apache2/error.log` or similar. - - For nginx, check both the nginx and php-fpm logs. - - For issues with the UI, check the Javascript error console in your web - browser. - - Some other things, like daemons, have their own debug flags or - troubleshooting steps. Check the documentation for information on - troubleshooting. Adjusting settings or enabling debugging modes may give - you more information about the issue. - - -Reproducibility -=============== - -The most important part of your report content is instructions on how to -reproduce the issue. What did you do? If you do it again, does it still break? -Does it depend on a specific browser? Can you reproduce the issue on a test -instance on `admin.phabricator.com`? - -It is nearly impossible for us to resolve many issues if we can not reproduce -them. We will not accept reports which do not contain the information required -to reproduce problems. - -For help, see @{article:Providing Reproduction Steps}. - - -File a Bug Report -================= - -If you're up to date, have collected information about the problem, and have -the best reproduction instructions you can come up with, you're ready -to file a report. - -It is **particularly critical** that you include reproduction steps. - -You can file a report on the community forum, here: - -(NOTE) https://discourse.phabricator-community.org/c/bug - - -Next Steps -========== - -Continue by: - - - reading general support information in @{article:Support Resources}; or - - returning to the @{article:Contributor Introduction}. diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/contrib_intro.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/contrib_intro.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/contrib_intro.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/contrib_intro.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -1,7 +1,7 @@ @title Contributor Introduction @group contrib -Introduction to contributing to Phabricator, Arcanist and libphutil. +Introduction to contributing to Phabricator and Arcanist. Overview ======== diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/contributing_code.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/contributing_code.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/contributing_code.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/contributing_code.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -1,238 +1,4 @@ @title Contributing Code @group detail -Describes how to contribute code to Phabricator. - -Level Requirements -================== - -To contribute to the Phabricator upstream, you must first pass a series of -ancient trials and be invited to register an account in the ancestral -homeland of Phabricator, here on `secure.phabricator.com`. The nature and -location of these trials is a closely guarded secret. - -If you have passed these trials, this document can guide you through -contributing code. - -If you have not yet passed these trials, writing code is normally not the best -way to contribute to Phabricator. See @{article:Contributor Introduction} for -more information. - - -Overview -======== - -If you're planning to send a patch to Phabricator, this guide can help you -through the process. The most important parts of contributing code to -Phabricator are: - - - File a task with a bug report or feature request //before// you write code. - - We rarely accept patches which we haven't discussed first. - - We do not accept patches against prototype applications. - - You must sign the CLA. - - We do not accept GitHub pull requests. - - Some alternative approaches are available if your change isn't something - we want to bring upstream. - -The rest of this article describes these points in more detail, and then -provides guidance on writing and submitting patches. - -If you just want to contribute some code but don't have a specific bug or -feature in mind, see the bottom of this document for tips on finding ways to get -started. - -For general information on contributing to Phabricator, see -@{article:Contributor Introduction}. - - -Coordinate First -================ - -Before sending code, you should file a task describing what you'd like to write. - -When you file a task, mention that you'd like to write the code to fix it. We -can help contextualize your request or bug and guide you through writing an -upstreamable patch, provided it's something that's upstreamable. If it isn't -upstreamable, we can let you know what the issues are and help find another -plan of attack. - -You don't have to file first (for example, if you spot a misspelling it's -normally fine to just send a diff), but for anything even moderately complex -you're strongly encouraged to file first and coordinate with the upstream. - - -Rejecting Patches -================= - -If you send us a patch without coordinating it with us first, it will probably -be immediately rejected, or sit in limbo for a long time and eventually be -rejected. The reasons we do this vary from patch to patch, but some of the most -common reasons are: - -**Unjustifiable Costs**: We support code in the upstream forever. Support is -enormously expensive and takes up a huge amount of our time. The cost to support -a change over its lifetime is often 10x or 100x or 1000x greater than the cost -to write the first version of it. Many uncoordinated patches we receive are -"white elephants", which would cost much more to maintain than the value they -provide. - -As an author, it may look like you're giving us free work and we're rejecting it -as too expensive, but this viewpoint doesn't align with the reality of a large -project which is actively supported by a small, experienced team. Writing code -is cheap; maintaining it is expensive. - -By coordinating with us first, you can make sure the patch is something we -consider valuable enough to put long-term support resources behind, and that -you're building it in a way that we're comfortable taking over. - -**Not a Good Fit**: Many patches aren't good fits for the upstream: they -implement features we simply don't want. Coordinating with us first helps -make sure we're on the same page and interested in a feature. - -The most common type of patch along these lines is a patch which adds new -configuration options. We consider additional configuration options to have -an exceptionally high lifetime support cost and are very unlikely to accept -them. Coordinate with us first. - -**Not a Priority**: If you send us a patch against something which isn't a -priority, we probably won't have time to look at it. We don't give special -treatment to low-priority issues just because there's code written: we'd still -be spending time on something lower-priority when we could be spending it on -something higher-priority instead. - -If you coordinate with us first, you can make sure your patch is in an area -of the codebase that we can prioritize. - -**Overly Ambitious Patches**: Sometimes we'll get huge patches from new -contributors. These can have a lot of fundamental problems and require a huge -amount of our time to review and correct. If you're interested in contributing, -you'll have more success if you start small and learn as you go. - -We can help you break a large change into smaller pieces and learn how the -codebase works as you proceed through the implementation, but only if you -coordinate with us first. - -**Generality**: We often receive several feature requests which ask for similar -features, and can come up with a general approach which covers all of the use -cases. If you send us a patch for //your use case only//, the approach may be -too specific. When a cleaner and more general approach is available, we usually -prefer to pursue it. - -By coordinating with us first, we can make you aware of similar use cases and -opportunities to generalize an approach. These changes are often small, but can -have a big impact on how useful a piece of code is. - -**Infrastructure and Sequencing**: Sometimes patches are written against a piece -of infrastructure with major planned changes. We don't want to accept these -because they'll make the infrastructure changes more difficult to implement. - -Coordinate with us first to make sure a change doesn't need to wait on other -pieces of infrastructure. We can help you identify technical blockers and -possibly guide you through resolving them if you're interested. - - -No Prototype Changes -==================== - -With rare exceptions, we do not accept patches for prototype applications for -the same reasons that we don't accept feature requests or bug reports. To learn -more about prototype applications, see -@{article:User Guide: Prototype Applications}. - - -You Must Sign the CLA -===================== - -Before we can accept source code contributions, you need to submit a -[[ https://secure.phabricator.com/L28 | Contributor License Agreement ]]. Your -changes can not be accepted until you sign the agreement. - -If you haven't signed it by the time you send changes for review, you'll be -reminded to sign it at that time. - -If you're submitting work on behalf of a company (like your employer), the -company can sign the [[ https://secure.phabricator.com/L30 | Corporate -Contributor License Agreement ]] instead. - -Both agreements are substantially similar to the Apache Foundation's CLAs. They -protect Phacility and users of Phabricator by making sure we have permission to -distribute your changes under an open source license. - - -No Pull Requests -================ - -We do not accept pull requests on GitHub: - - - We can not monitor who has signed CLAs on GitHub. You must sign the CLA - to contribute, and we can't tell if you've signed it or not when you send - us a pull request. - - Pull requests do not get lint and unit tests run, so issues which are - normally caught statically can slip by. - - Phabricator is code review software, and developed using its own workflows. - Pull requests bypass some of these workflows (for example, they will not - trigger Herald rules to notify interested parties). - - GitHub is not the authoritative master repository and we maintain a linear - history, so merging pull requests is cumbersome on our end. - - If you're comfortable enough with Phabricator to contribute to it, you - should also be comfortable using it to submit changes. - -Instead of sending a pull request, use `arc diff` to create a revision on the -upstream install. Your change will go through the normal Phabricator review -process. - -(GitHub does not allow repositories to disable pull requests, which is why -it's technically possible to submit them.) - - -Alternatives -============ - -If you've written code but we're not accepting it into the upstream, some -alternative approaches include: - -**Maintain a local fork.** This will require some ongoing effort to port your -changes forward when you update, but is often very reasonable for simple -changes. - -**Develop as an application.** Many parts of Phabricator's infrastructure are -modular, and modularity is increasing over time. A lot of changes can be built -as external modules or applications without forking Phabricator itself. There -isn't much documentation or support for this right now, but you can look at -how other applications are implemented, and at other third-party code that -extends Phabricator. - -**Rise to prominence.** We're more willing to accept borderline changes from -community members who are active, make multiple contributions, or have a history -with the project. This is not carte blanche, but distinguishing yourself can -make us feel more comfortable about supporting a change which is slightly -outside of our comfort zone. - - -Writing and Submitting Patches -================== - -To actually submit a patch, run `arc diff` in `phabricator/`, `arcanist/`, or -`libphutil/`. When executed in these directories, `arc` should automatically -talk to the upstream install. You can add `epriestley` as a reviewer. - -You should read the relevant coding convention documents before you submit a -change. If you're a new contributor, you don't need to worry about this too -much. Just try to make your code look similar to the code around it, and we -can help you through the details during review. - - - @{article:General Coding Standards} (for all languages) - - @{article:PHP Coding Standards} (for PHP) - - @{article:Javascript Coding Standards} (for Javascript) - -In general, if you're coordinating with us first, we can usually provide -guidance on how to implement things. The other articles in this section also -provide information on how to work in the Phabricator codebase. - - -Next Steps -========== - -Continue by: - - - returning to the @{article:Contributor Introduction}. +Effective June 1, 2021: Phabricator is no longer actively maintained, and no longer accepting contributions. diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/feature_requests.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/feature_requests.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/feature_requests.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/feature_requests.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -1,232 +1,4 @@ @title Contributing Feature Requests @group detail -Describes how to file an effective Phabricator feature request. - - -Level Requirements -================== - -We accept feature requests through two channels: paid support and community -support. - -If you are a paying customer, use the -[[ https://admin.phacility.com/u/support | Support Channel ]] for your account -to request features. This document may help you frame your requests in a way -that lets us address them more quickly, but you do not need to read it or -follow the guidelines. - -Other users can file requests on the -[[ https://phurl.io/u/discourse | community forum ]]. - - -Overview -======== - -This article describes how to file an effective feature request. - -The most important things to do are: - - - understand the upstream; - - make sure your feature makes sense in the project; - - align your expectations around timelines and priorities; - - describe your problem, not your solution. - -The rest of this article walks through these points in detail. - -If you have a bug report (not a feature request), see -@{article:Contributing Bug Reports} for a more tailored guide. - -For general information on contributing to Phabricator, see -@{article:Contributor Introduction}. - - -Understanding the Upstream -========================== - -Before filing a feature request, it may be useful to understand how the -upstream operates. - -The Phabricator upstream is [[ https://www.phacility.com | Phacility, Inc ]]. -We maintain total control over the project and roadmap. There is no democratic -process, voting, or community-driven decision making. This model is better -at some things and worse at others than a more community-focused model would -be, but it is the model we operate under. - -We have a cohesive vision for the project in the long term, and a general -roadmap that extends for years into the future. While the specifics of how -we get there are flexible, many major milestones are well-established. - -Although we set project direction, the community is also a critical part of -Phabricator. We aren't all-knowing, and we rely on feedback to help us identify -issues, guide product direction, prioritize changes, and suggest features. - -Feature requests are an important part of this, but we ultimately build only -features which make sense as part of the long term plan. - -Since it's hard to absorb a detailed understanding of that vision, //describing -a problem// is often more effective than //requesting a feature//. We have the -context to develop solutions which fit into our plans, address similar use -cases, make sense with the available infrastructure, and work within the -boundaries of our product vision. For more details on this, see below. - - -Target Audiences -================ - -Some feature requests support very unusual use cases. Although we are broadly -inclusive of many different kinds of users and use cases, we are not trying -to make the software all things to all users. Use cases which are far afield -from the things the majority of users do with Phabricator often face substantial -barriers. - -Phabricator is primarily targeted at software projects and organizations with -a heavy software focus. We are most likely to design, build, and prioritize -features which serve these organizations and projects. - -Phabricator is primarily targeted at software professionals and other -professionals with adjacent responsibilities (like project management and -operations). Particularly, we assume users are proficient computer users and -familiar with software development concepts. We are most likely to design, build -and prioritize features which serve these users. - -Phabricator is primarily targeted at professionals working in teams on full-time -projects. Particularly, we assume most users will use the software regularly and -are often willing to spend a little more time up front to get a more efficient -workflow in the long run. We are most likely to design, build and prioritize -features which serve these use cases. - -Phabricator is not limited to these kinds of organizations, users and use cases, -but features which are aimed at a different group of users (like students, -casual projects, or inexperienced computer users) may be harder to get -upstreamed. Features aimed at very different groups of users (like wedding -planners, book clubs, or dogs) will be much harder to get upstreamed. - -In many cases, a feature makes something better for all users. For example, -suppose we fixed an issue where colorblind users had difficulty doing something. -Dogs would benefit the most, but colorblind human users would also benefit, and -no one would be worse off. If the benefit for core users is very small these -kinds of features may be hard to prioritize, but there is no exceptional barrier -to getting them upstreamed. - -In other cases, a feature makes something better for some users and worse for -other users. These kinds of features face a high barrier if they make the -software better at planning weddings and worse at reviewing code. - - -Setting Expectations -==================== - -We have a lot of users and a small team. Even if your feature is something we're -interested in and a good fit for where we want the product to go, it may take -us a long time to get around to building it. - -We work full time on Phabricator, and our long-term roadmap (which we call our -[[ https://secure.phabricator.com/w/starmap/ | Starmap ]]) has many years worth -of work. Your feature request is competing against thousands of other requests -for priority. - -In general, we try to prioritize work that will have the greatest impact on the -most users. Many feature requests are perfectly reasonable requests, but have -very little impact, impact only a few users, and/or are complex to develop and -support relative to their impact. It can take us a long time to get to these. - -Even if your feature request is simple and has substantial impact for a large -number of users, the size of the request queue means that it is mathematically -unlikely to be near the top. - -You can find some information about how we prioritize in -[[ https://secure.phabricator.com/w/planning/ | Planning ]]. In particular, -we reprioritize frequently and can not accurately predict when we'll build a -feature which isn't very near to top of the queue. - -As a whole, this means that the overwhelming majority of feature requests will -sit in queue for a long time without any updates, and that we won't be able to -give you any updates or predictions about timelines. One day, out of nowhere, -your feature will materialize. That day may be a decade from now. You should -have realistic expectations about this when filing a feature request. - - -Describe Problems -================= - -When you file a feature request, we need you to describe the problem you're -facing first, not just your desired solution. Describing the problem you are -facing is the **most important part** of a feature request. - -Often, your problem may have a lot in common with other similar problems. If we -understand your use case we can compare it to other use cases and sometimes find -a more powerful or more general solution which solves several problems at once. - -At other times, we'll have a planned solution to the problem that might be -different from your desired solution but accomplish the same goal. Understanding -the root issue can let us merge and contextualize things. - -Sometimes there's already a way to solve your problem that might just not be -obvious. - -Finally, your proposed solution may not be compatible with the direction we -want to take the product, but we may be able to come up with another solution -which has approximately the same effect and does fit into the product direction. - -If you only describe the solution and not the problem, we can't generalize, -contextualize, merge, reframe, or offer alternative solutions or workarounds. - -You must describe the problem you are facing when filing a feature request. We -will not accept feature requests which do not contextualize the request by -describing the root problem. - -If you aren't sure exactly what we're after when we ask you to describe a root -problem, you can find examples and more discussion in -@{article:Describing Root Problems}. - - -Hypotheticals -============= - -We sometimes receive hypothetical feature requests about anticipated problems -or concerns which haven't actually occurred yet. We usually can't do much about -these until the problems actually occur, since the context required to -understand and properly fix the root issue won't exist. - -One situation where this happens is when installs are thinking about adopting -Phabricator and trying to guess what problems users might encounter during the -transition. More generally, this includes any request like "if users do **X**, -they might find **Y** confusing", where no actual users have encountered -confusion yet. - -These requests are necessarily missing important context, maybe including the -answers to questions like these: - - - Why did users do **X**? - - What were they trying to do? - - What did they expect to happen? - - How often do users do this? - -The answers to these questions are important in establishing that the issue is -really a problem, figuring out the best solution for it, and prioritizing the -issue relative to other issues. - -Without knowing this information, we can't be confident that we've found a good -solution to the problem, can't know if we've actually fixed the problem, and -can't even know if the issue was really a problem in the first place (some -hypothetical requests describe problems which no users ever encounter). - -We usually can't move forward without this information. In particular, we don't -want to spend time solving hypothetical problems which no real users will ever -encounter: the value of those changes is zero (or negative, by making the -product more complex without providing a benefit), but they consume development -time which could be better spent building much more valuable features. - -Generally, you should wait until a problem actually occurs before filing a -request about it. - - -Next Steps -========== - -Continue by: - - - learning about @{article: Contributing Bug Reports}; or - - reading general support information in @{article:Support Resources}; or - - returning to the @{article:Contributor Introduction}. +Effective June 1, 2021: Phabricator is no longer actively maintained, and there is no way to file a feature request. diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/general_coding_standards.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/general_coding_standards.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/general_coding_standards.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/general_coding_standards.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -2,7 +2,7 @@ @group standards This document is a general coding standard for contributing to Phabricator, -Arcanist, libphutil and Diviner. +Arcanist, and Diviner. = Overview = @@ -136,7 +136,7 @@ Filesystem::writeFile('file.bak', $data); // Best do_something_dangerous(); -See @{article@libphutil:Command Execution} for details on the APIs used in this +See @{article@arcanist:Command Execution} for details on the APIs used in this example. = Documentation, Comments and Formatting = diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/internationalization.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/internationalization.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/internationalization.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/internationalization.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -44,7 +44,7 @@ Writing Translatable Code ========================= -Strings are marked for translation with @{function@libphutil:pht}. +Strings are marked for translation with @{function@arcanist:pht}. The `pht()` function takes a string (and possibly some parameters) and returns the translated version of that string in the current viewer's locale, if a @@ -68,7 +68,7 @@ - Use parameters to create strings containing user names, object names, etc. - Translate full sentences, not sentence fragments. - Let the translation framework handle plural rules. - - Use @{class@libphutil:PhutilNumber} for numbers. + - Use @{class@arcanist:PhutilNumber} for numbers. - Let the translation framework handle subject gender rules. - Translate all human-readable text, even exceptions and error messages. @@ -323,7 +323,7 @@ languages, and languages like Czech also require verb agreement. When a parameter refers to a gendered person, pass an object which implements -@{interface@libphutil:PhutilPerson} to `pht()` so translators can provide +@{interface@arcanist:PhutilPerson} to `pht()` so translators can provide gendered translation variants. ```lang=php @@ -361,8 +361,8 @@ In cases where similar error or exception text is often repeated, it is probably appropriate to define an exception for that category of error rather than write the text out repeatedly, anyway. Two examples are -@{class@libphutil:PhutilInvalidStateException} and -@{class@libphutil:PhutilMethodNotImplementedException}, which mostly exist to +@{class@arcanist:PhutilInvalidStateException} and +@{class@arcanist:PhutilMethodNotImplementedException}, which mostly exist to produce a consistent message about a common error state in a convenient way. There are a handful of error strings in the codebase which may be used before diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/php_coding_standards.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/php_coding_standards.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/php_coding_standards.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/php_coding_standards.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -2,13 +2,13 @@ @group standards This document describes PHP coding standards for Phabricator and related -projects (like Arcanist and libphutil). +projects (like Arcanist). = Overview = This document outlines technical and style guidelines which are followed in -libphutil. Contributors should also follow these guidelines. Many of these -guidelines are automatically enforced by lint. +Phabricator and Arcanist. Contributors should also follow these guidelines. +Many of these guidelines are automatically enforced by lint. These guidelines are essentially identical to the Facebook guidelines, since I basically copy-pasted them. If you are already familiar with the Facebook diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/rendering_html.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/rendering_html.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/rendering_html.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/rendering_html.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -13,13 +13,13 @@ This document describes the right way to build HTML components so they are safe from XSS and render correctly. Broadly: - - Use @{function@libphutil:phutil_tag} (and @{function:javelin_tag}) to build + - Use @{function@arcanist:phutil_tag} (and @{function:javelin_tag}) to build tags. - - Use @{function@libphutil:hsprintf} where @{function@libphutil:phutil_tag} + - Use @{function@arcanist:hsprintf} where @{function@arcanist:phutil_tag} is awkward. - Combine elements with arrays, not string concatenation. - @{class:AphrontView} subclasses should return a - @{class@libphutil:PhutilSafeHTML} object from their `render()` method. + @{class@arcanist:PhutilSafeHTML} object from their `render()` method. - @{class:AphrontView} subclasses act like tags when rendering. - @{function:pht} has some special rules. - There are some other things that you should be aware of. @@ -28,7 +28,7 @@ = Building Tags: phutil_tag() = -Build HTML tags with @{function@libphutil:phutil_tag}. For example: +Build HTML tags with @{function@arcanist:phutil_tag}. For example: phutil_tag( 'div', @@ -37,10 +37,10 @@ ), $content); -@{function@libphutil:phutil_tag} will properly escape the content and all the -attributes, and return a @{class@libphutil:PhutilSafeHTML} object. The rendering +@{function@arcanist:phutil_tag} will properly escape the content and all the +attributes, and return a @{class@arcanist:PhutilSafeHTML} object. The rendering pipeline knows that this object represents a properly escaped HTML tag. This -allows @{function@libphutil:phutil_tag} to render tags with other tags as +allows @{function@arcanist:phutil_tag} to render tags with other tags as content correctly (without double-escaping): phutil_tag( @@ -52,14 +52,14 @@ $content)); In Phabricator, the @{function:javelin_tag} function is similar to -@{function@libphutil:phutil_tag}, but provides special handling for the +@{function@arcanist:phutil_tag}, but provides special handling for the `sigil` and `meta` attributes. = Building Blocks: hsprintf() = -Sometimes, @{function@libphutil:phutil_tag} can be particularly awkward to -use. You can use @{function@libphutil:hsprintf} to build larger and more -complex blocks of HTML, when @{function@libphutil:phutil_tag} is a poor fit. +Sometimes, @{function@arcanist:phutil_tag} can be particularly awkward to +use. You can use @{function@arcanist:hsprintf} to build larger and more +complex blocks of HTML, when @{function@arcanist:phutil_tag} is a poor fit. @{function:hsprintf} has `sprintf()` semantics, but `%s` escapes HTML: // Safely build fragments or unwieldy blocks. @@ -72,13 +72,13 @@ - You need to build a block with a lot of tags, like a table with rows and cells. - You need to build part of a tag (usually you should avoid this, but if you - do need to, @{function@libphutil:phutil_tag} can not do it). + do need to, @{function@arcanist:phutil_tag} can not do it). Note that it is unsafe to provide any user-controlled data to the first -parameter of @{function@libphutil:hsprintf} (the `sprintf()`-style pattern). +parameter of @{function@arcanist:hsprintf} (the `sprintf()`-style pattern). -Like @{function@libphutil:phutil_tag}, this function returns a -@{class@libphutil:PhutilSafeHTML} object. +Like @{function@arcanist:phutil_tag}, this function returns a +@{class@arcanist:PhutilSafeHTML} object. = Composing Tags = @@ -99,7 +99,7 @@ // Render a tag containing other tags safely. phutil_tag('div', array(), array($header, $body)); -If you concatenate @{class@libphutil:PhutilSafeHTML} objects, they revert to +If you concatenate @{class@arcanist:PhutilSafeHTML} objects, they revert to normal strings and are no longer marked as properly escaped tags. (In the future, these objects may stop converting to strings, but for now they @@ -118,7 +118,7 @@ = AphrontView Classes = Subclasses of @{class:AphrontView} in Phabricator should return a -@{class@libphutil:PhutilSafeHTML} object. The easiest way to do this is to +@{class@arcanist:PhutilSafeHTML} object. The easiest way to do this is to return `phutil_tag()` or `javelin_tag()`: return phutil_tag('div', ...); @@ -130,8 +130,8 @@ = Internationalization: pht() = The @{function:pht} function has some special rules. If any input to -@{function:pht} is a @{class@libphutil:PhutilSafeHTML} object, @{function:pht} -returns a @{class@libphutil:PhutilSafeHTML} object itself. Otherwise, it returns +@{function:pht} is a @{class@arcanist:PhutilSafeHTML} object, @{function:pht} +returns a @{class@arcanist:PhutilSafeHTML} object itself. Otherwise, it returns normal text. This is generally safe because translations are not permitted to have more tags @@ -146,23 +146,23 @@ NOTE: This section describes dangerous methods which can bypass XSS protections. If possible, do not use them. -You can build @{class@libphutil:PhutilSafeHTML} out of a string explicitly by +You can build @{class@arcanist:PhutilSafeHTML} out of a string explicitly by calling @{function:phutil_safe_html} on it. This is **dangerous**, because if you are wrong and the string is not actually safe, you have introduced an XSS vulnerability. Consequently, you should avoid calling this if possible. -You can use @{function@libphutil:phutil_escape_html_newlines} to escape HTML +You can use @{function@arcanist:phutil_escape_html_newlines} to escape HTML while converting newlines to `<br />`. You should not need to explicitly use -@{function@libphutil:phutil_escape_html} anywhere. +@{function@arcanist:phutil_escape_html} anywhere. If you need to apply a string function (such as `trim()`) to safe HTML, use -@{method@libphutil:PhutilSafeHTML::applyFunction}. +@{method@arcanist:PhutilSafeHTML::applyFunction}. -If you need to extract the content of a @{class@libphutil:PhutilSafeHTML} +If you need to extract the content of a @{class@arcanist:PhutilSafeHTML} object, you should call `getHTMLContent()`, not cast it to a string. Eventually, we would like to remove the string cast entirely. -Functions @{function@libphutil:phutil_tag} and @{function@libphutil:hsprintf} +Functions @{function@arcanist:phutil_tag} and @{function@arcanist:hsprintf} are not safe if you pass the user input for the tag or attribute name. All the following examples are dangerous: diff -Nru phabricator-0~git20200925/phabricator/src/docs/contributor/unit_tests.diviner phabricator-0~git20220903/phabricator/src/docs/contributor/unit_tests.diviner --- phabricator-0~git20200925/phabricator/src/docs/contributor/unit_tests.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/contributor/unit_tests.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -1,13 +1,13 @@ @title Writing Unit Tests @group developer -Simple guide to libphutil, Arcanist and Phabricator unit tests. +Simple guide to Arcanist and Phabricator unit tests. = Overview = -libphutil, Arcanist and Phabricator provide and use a simple unit test -framework. This document is aimed at project contributors and describes how to -use it to add and run tests in these projects or other libphutil libraries. +Arcanist and Phabricator provide and use a simple unit test framework. This +document is aimed at project contributors and describes how to use it to add +and run tests in these projects or other libphutil libraries. In the general case, you can integrate `arc` with a custom unit test engine (like PHPUnit or any other unit testing library) to run tests in other projects. @@ -16,7 +16,7 @@ = Adding Tests = -To add new tests to a libphutil, Arcanist or Phabricator module: +To add new tests to a Arcanist or Phabricator module: - Create a `__tests__/` directory in the module if it doesn't exist yet. - Add classes to the `__tests__/` directory which extend from diff -Nru phabricator-0~git20200925/phabricator/src/docs/flavor/php_pitfalls.diviner phabricator-0~git20220903/phabricator/src/docs/flavor/php_pitfalls.diviner --- phabricator-0~git20200925/phabricator/src/docs/flavor/php_pitfalls.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/flavor/php_pitfalls.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -18,7 +18,7 @@ intermediate arrays and copies every element it has previously seen each time you iterate. -In a libphutil environment, you can use @{function@libphutil:array_mergev} +In a libphutil environment, you can use @{function@arcanist:array_mergev} instead. = `var_export()` Hates Baby Animals = @@ -147,7 +147,7 @@ instead, and use it to reorder the original array. In a libphutil environment, you can often do this easily with -@{function@libphutil:isort} or @{function@libphutil:msort}. +@{function@arcanist:isort} or @{function@arcanist:msort}. = `array_intersect()` and `array_diff()` are Also Slow = @@ -270,7 +270,7 @@ ...you'll probably invent a very interesting, very novel solution that is very wrong. In a libphutil environment, solve this problem with -@{function@libphutil:newv}. Elsewhere, copy `newv()`'s implementation. +@{function@arcanist:newv}. Elsewhere, copy `newv()`'s implementation. = Equality is not Transitive = diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/cluster/cluster_repositories.diviner phabricator-0~git20220903/phabricator/src/docs/user/cluster/cluster_repositories.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/cluster/cluster_repositories.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/cluster/cluster_repositories.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -523,6 +523,87 @@ data more easily in a wider range of disaster situations. +Ad-Hoc Maintenance Locks +======================== + +Occasionally, you may want to perform maintenance to a clustered repository +which requires you modify the actual content of the repository. + +For example: you might want to delete a large number of old or temporary +branches; or you might want to merge a very large number of commits from +another source. + +These operations may be prohibitively slow or complex to perform using normal +pushes. In cases where you would prefer to directly modify a working copy, you +can use a maintenance lock to safely make a working copy mutable. + +If you simply perform this kind of content-modifying maintenance by directly +modifying the repository on disk with commands like `git update-ref`, your +changes may either encounter conflicts or encounter problems with change +propagation. + +You can encounter conflicts because directly modifying the working copy on disk +won't prevent users or Phabricator itself from performing writes to the same +working copy at the same time. Phabricator does not compromise the lower-level +locks provided by the VCS so this is theoretically safe -- and this rarely +causes any significant problems in practice -- but doesn't make things any +simpler or easier. + +Your changes may fail to propagate because writing directly to the repository +doesn't turn it into the new cluster leader after your writes complete. If +another node accepts the next push, it will become the new leader -- without +your changes -- and all other nodes will synchronize from it. + +Note that some maintenance operations (like `git gc`, `git prune`, or +`git repack`) do not modify repository content. In theory, these operations do +not require a maintenance lock: lower-level Git locks should protect +them from conflicts, and they can not be affected by propagation issues because +they do not propagate. In practice, these operations are not conflict-free in +all circumstances. Using a maintenance lock may be overkill, but it's probably +still a good idea. + +To use a maintenance lock: + + - Open two terminal windows. You'll use one window to hold the lock and a + second window to perform maintenance. + - Run `bin/repository lock <repository> ...` in one terminal. + - When the process reports that repositories are locked, switch to the second + terminal and perform maintenance. The `repository lock` process should + still be running in your first terminal. + - After maintenance completes, switch back to the first terminal and answer + the prompt to confirm maintenance is complete. + +The workflow looks something like this: + +``` +$ ./bin/repository lock R2 + +These repositories will be locked: + + - R2 Git Test Repository + +While the lock is held: users will be unable to write to this repository, +and you may safely perform working copy maintenance on this node in another +terminal window. + + Lock repositories and begin maintenance? [y/N] y + +Repositories are now locked. You may begin maintenance in another terminal +window. Keep this process running until you complete the maintenance, then +confirm that you are ready to release the locks. + + Ready to release the locks? [y/N] y + +Done. +``` + +As maintenance completes, the push log for the repository will be updated to +reflect that you performed maintenance. + +If the lock is interrupted, you may encounter a "Write Interruptions" condition +described earlier in this document. See that section for details. In most +cases, you can resolve this issue by demoting the node you are working on. + Next Steps ========== diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/configuration/advanced_configuration.diviner phabricator-0~git20220903/phabricator/src/docs/user/configuration/advanced_configuration.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/configuration/advanced_configuration.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/configuration/advanced_configuration.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -21,7 +21,7 @@ - **Database**: Values are stored in the database and edited from the web UI by administrators. They have the highest priority and override other settings. - - **Local**: Values are stored in `conf/local/config.json` and edited by + - **Local**: Values are stored in `conf/local/local.json` and edited by running `bin/config`. - **Config Files**: Values are stored in a config file in `conf/`. The file to use is selected by writing to `conf/local/ENVIRONMENT`, or setting the diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/configuration/configuring_inbound_email.diviner phabricator-0~git20220903/phabricator/src/docs/user/configuration/configuring_inbound_email.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/configuration/configuring_inbound_email.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/configuration/configuring_inbound_email.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -42,9 +42,9 @@ | Receive Mail With | Setup | Cost | Notes | |--------|-------|------|-------| -| Mailgun | Easy | Cheap | Recommended | | Postmark | Easy | Cheap | Recommended | | SendGrid | Easy | Cheap | | +| Mailgun | Easy | Cheap | Discouraged | | Local MTA | Difficult | Free | Discouraged | The remainder of this document walks through configuring Phabricator to @@ -183,6 +183,9 @@ example domain with your actual domain. - Configure a mailer in `cluster.mailers` with your Mailgun API key. +Use of Mailgun is discouraged because of concerns that they may not be a +trustworthy custodian of sensitive data. See <https://phurl.io/u/mailgun> for +discussion and context. Postmark Setup ============== diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/configuration/configuring_outbound_email.diviner phabricator-0~git20220903/phabricator/src/docs/user/configuration/configuring_outbound_email.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/configuration/configuring_outbound_email.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/configuration/configuring_outbound_email.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -17,7 +17,6 @@ | Send Mail With | Setup | Cost | Inbound | Media | Notes | |----------------|-------|------|---------|-------|-------| | Postmark | Easy | Cheap | Yes | Email | Recommended | -| Mailgun | Easy | Cheap | Yes | Email | Recommended | | Amazon SES | Easy | Cheap | No | Email | | | SendGrid | Medium | Cheap | Yes | Email | | | Twilio | Easy | Cheap | No | SMS | Recommended | @@ -26,14 +25,15 @@ | Local SMTP | Hard | Free | No | Email | sendmail, postfix, etc | | Custom | Hard | Free | No | All | Write a custom mailer. | | Drop in a Hole | Easy | Free | No | All | Drops mail in a deep, dark hole. | +| Mailgun | Easy | Cheap | Yes | Email | Discouraged | See below for details on how to select and configure mail delivery for each mailer. -For email, Postmark or Mailgun are recommended because they make it easy to -set up inbound and outbound mail and have good track records in our production -services. Other services will also generally work well, but they may be more -difficult to set up. +For email, Postmark is recommended because it makes it easy to set up inbound +and outbound mail and has a good track record in our production services. Other +services will also generally work well, but they may be more difficult to set +up. For SMS, Twilio or SNS are recommended. They're also your only upstream options. @@ -87,8 +87,8 @@ ```lang=json [ { - "key": "mycompany-mailgun", - "type": "mailgun", + "key": "mycompany-postmark", + "type": "postmark", "options": { "domain": "mycompany.com", "api-key": "..." @@ -118,12 +118,12 @@ The `type` field can be used to select these mailer services: - - `mailgun`: Use Mailgun. - `ses`: Use Amazon SES. - `sendgrid`: Use SendGrid. - `postmark`: Use Postmark. - `twilio`: Use Twilio. - `sns`: Use Amazon SNS. + - `mailgun`: Use Mailgun. It also supports these local mailers: @@ -204,11 +204,12 @@ [ "50.31.156.6/32", "50.31.156.77/32", - "18.217.206.57/32" + "18.217.206.57/32", + "3.134.147.250/32" ] ``` -The default address ranges were last updated in January 2019, and were +The default address ranges were last updated in December 2021, and were documented at: <https://postmarkapp.com/support/article/800-ips-for-firewalls> @@ -220,6 +221,10 @@ | Inbound | Yes |---------| +Use of Mailgun is discouraged because of concerns that they may not be a +trustworthy custodian of sensitive data. See <https://phurl.io/u/mailgun> for +discussion and context. + Mailgun is a third-party email delivery service. You can learn more at <https://www.mailgun.com>. Mailgun is easy to configure and works well. @@ -339,7 +344,7 @@ rules, blackholes, and MTA configuration which are beyond the scope of this document. If you can already send outbound email from the command line or know how to configure it, this option is straightforward. If you have no idea how to -do any of this, strongly consider using Postmark or Mailgun instead. +do any of this, strongly consider using Postmark instead. To use this mailer, set `type` to `sendmail`, then configure these `options`: @@ -416,7 +421,7 @@ next group. For example, if you have two SMTP servers and you want to balance requests -between them and then fall back to Mailgun if both fail, configure priorities +between them and then fall back to Postmark if both fail, configure priorities like this: ```lang=json @@ -434,8 +439,8 @@ "options": "..." }, { - "key": "mailgun-fallback", - "type": "mailgun", + "key": "postmark-fallback", + "type": "postmark", "options": "..." } } @@ -450,7 +455,7 @@ If it still hasn't sent the mail, Phabricator will try servers which are not in any priority group, in the configured order. In this example there is -only one such server, so it will try to send via Mailgun. +only one such server, so it will try to send via Postmark. Message-ID Headers diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/configuration/managing_daemons.diviner phabricator-0~git20220903/phabricator/src/docs/user/configuration/managing_daemons.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/configuration/managing_daemons.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/configuration/managing_daemons.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -65,7 +65,7 @@ You can get a list of launchable daemons with **phd list**: - - **libphutil test daemons** are not generally useful unless you are + - **test daemons** are not generally useful unless you are developing daemon infrastructure or debugging a daemon problem; - **PhabricatorTaskmasterDaemon** performs work from a task queue; - **PhabricatorRepositoryPullLocalDaemon** daemons track repositories, for diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/configuration/troubleshooting_https.diviner phabricator-0~git20220903/phabricator/src/docs/user/configuration/troubleshooting_https.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/configuration/troubleshooting_https.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/configuration/troubleshooting_https.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -32,7 +32,7 @@ You can self-sign a certificate by creating your own CA, but clients will not trust it by default. They need to add the CA as a trusted authority. -For instructions on adding CAs, see `libphutil/resources/ssl/README`. +For instructions on adding CAs, see `arcanist/resources/ssl/README`. If you'd prefer that `arc` not verify the identity of the server whatsoever, you can use the `https.blindly-trust-domains` setting. This will make it diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/field/darkconsole.diviner phabricator-0~git20220903/phabricator/src/docs/user/field/darkconsole.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/field/darkconsole.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/field/darkconsole.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -48,7 +48,7 @@ The "Error Log" plugin shows errors that occurred while generating the page, similar to the httpd `error.log`. You can send information to the error log -explicitly with the @{function@libphutil:phlog} function. +explicitly with the @{function@arcanist:phlog} function. If errors occurred, a red dot will appear on the plugin tab. diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/field/worker_queue.diviner phabricator-0~git20220903/phabricator/src/docs/user/field/worker_queue.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/field/worker_queue.diviner 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/field/worker_queue.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,83 @@ +@title Managing the Worker Queue +@group fieldmanual + +Advanced guide to managing the background worker task queue. + +Overview +======== + +Phabricator uses daemonized worker processes to execute some tasks (like +importing repositories and sending mail) in the background. + +In most cases, this queue will automatically execute tasks in an appropriate +order. However, in some cases you may want to exercise greater control over +which tasks execute, when, and at what priority. + +Reference: Priority Levels +========================== + +Tasks queued by Phabricator use these default priority levels: + +| Priority | Name | Tasks | +|---|---|---| +| 1000 | `ALERTS` | Time-sensitive notifications and email. | +| 2000 | `DEFAULT` | Normal publishing and processing. | +| 2500 | `COMMIT` | Import of commits in existing repositories. | +| 3000 | `BULK` | Edits applied via "Bulk Edit" interface. | +| 3500 | `INDEX` | Search engine index updates. | +| 4000 | `IMPORT` | Import of commits in new repositories. | + +Tasks with smaller priority numbers execute before tasks with larger priority +numbers (for example, a task with priority 1000 will execute before a task +with priority 2000). + +Any positive integer is a valid priority level, and if you adjust the priority +of tasks with `bin/worker priority` you may select any level even if +Phabricator would never naturally queue tasks at that level. For example, you +may adjust tasks to priority `5678`, which will make them execute after all +other types of natural tasks. + +Although tasks usually execute in priority order, task execution order is not +strictly a function of priority, and task priority does not guarantee execution +order. + +Large Repository Imports +======================== + +The most common case where you may want to make an adjustment to the default +behavior of the worker queue is when importing a very large repository like +the Linux kernel. + +Although Phabricator will automatically process imports of new repositories at +a lower priority level than all other non-import tasks, you may still run into +issues like these: + + - You may also want to import one or more //other// new repositories, and + would prefer they import at a higher priority. + - You may find overall repository performance is impacted by the large + repository import. + +You can manually change the priority of tasks with `bin/worker priority`. For +example, if your copy of the Linux repository is `R123` and you'd like it to +import at a lower priority than all other tasks (including other imports of +new repositories), you can run a command like this: + +``` +phabricator/ $ ./bin/worker priority --priority 5000 --container R123 +``` + +This means: set all tasks associated with container `R123` (in this example, +the Linux repository) to priority 5000 (which is lower than any natural +priority). + +You can delay tasks until later with `bin/worker delay`, which allows you to +schedule tasks to execute at night or over the weekend. For example, to +pause an import for 6 hours, run a command like this: + +``` +phabricator/ $ ./bin/worker delay --until "6 hours" --container R123 +``` + +The selected tasks will not execute until 6 hours from the time this command +is issued. You can also provide an explicit date, or "now" to let tasks begin +execution immediately. diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/installation_guide.diviner phabricator-0~git20220903/phabricator/src/docs/user/installation_guide.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/installation_guide.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/installation_guide.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -64,13 +64,14 @@ works fine. - **Other**: Other webservers which can run PHP are also likely to work fine, although these installation instructions will not cover how to set them up. - - **PHP Builtin Server**: You can use the builtin PHP webserver for - development or testing, although it should not be used in production. + - **PHP Builtin Server**: Phabricator will not work with the builtin + webserver because Phabricator depends on making requests to itself on some + workflows, and the builtin webserver is single-threaded. You will also need: - **MySQL**: You need MySQL. We strongly recommend MySQL 5.5 or newer. - - **PHP**: You need PHP 5.2 or newer. + - **PHP**: You need PHP 5.5 or newer. You'll probably also need a **domain name**. In particular, you should read this note: @@ -101,22 +102,7 @@ Installing Required Components ============================== -If you are installing on Ubuntu or an RedHat derivative, there are install -scripts available which should handle most of the things discussed in this -document for you: - - - **RedHat Derivatives**: - [[ https://secure.phabricator.com/diffusion/P/browse/master/scripts/install/install_rhel-derivs.sh - | install_rhel-derivs.sh ]] - - **Ubuntu**: - [[ https://secure.phabricator.com/diffusion/P/browse/master/scripts/install/install_ubuntu.sh - | install_ubuntu.sh ]] - -If those work for you, you can skip directly to the -@{article:Configuration Guide}. These scripts are also available in the -`scripts/install` directory in the project itself. - -Otherwise, here's a general description of what you need to install: +Here's a general description of what you need to install: - git (usually called "git" in package management systems) - Apache (usually "httpd" or "apache2") (or nginx) @@ -124,9 +110,7 @@ - PHP (usually "php") - Required PHP extensions: mbstring, iconv, mysql (or mysqli), curl, pcntl (these might be something like "php-mysql" or "php5-mysqlnd") - - Optional PHP extensions: gd, apc (special instructions for APC are available - below if you have difficulty installing it), xhprof (instructions below, - you only need this if you are developing Phabricator) + - Optional PHP extensions: gd If you already have LAMP setup, you've probably already got everything you need. It may also be helpful to refer to the install scripts above, even if they don't @@ -136,41 +120,11 @@ dependencies: $ cd somewhere/ # pick some install directory - somewhere/ $ git clone https://github.com/phacility/libphutil.git somewhere/ $ git clone https://github.com/phacility/arcanist.git somewhere/ $ git clone https://github.com/phacility/phabricator.git -= Installing APC (Optional) = - -Like everything else written in PHP, Phabricator will run much faster with APC -installed. You likely need to install "pcre-devel" first: - - sudo yum install pcre-devel - -Then you have two options. Either install via PECL (try this first): - - sudo yum install php-pear - sudo pecl install apc - -**If that doesn't work**, grab the package from PECL directly and follow the -build instructions there: - -http://pecl.php.net/package/APC - -Installing APC is optional but **strongly recommended**, especially on -production hosts. - -Once APC is installed, test that it is available by running: - - php -i | grep apc - -If it doesn't show up, add: - - extension=apc.so - -..to "/etc/php.d/apc.ini" or the "php.ini" file indicated by "php -i". - -= Next Steps = +Next Steps +========== Continue by: diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/support.diviner phabricator-0~git20220903/phabricator/src/docs/user/support.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/support.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/support.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -2,91 +2,4 @@ @short Support @group intro -Resources for reporting bugs, requesting features, and getting support. - -Overview -======== - -This document describes available support resources. - -The upstream provides free support for a narrow range of problems (primarily, -security issues and reproducible bugs) and paid support for virtually anything. - -The upstream does not provide free support for general problems with installing -or configuring Phabricator. You may be able to get some help with these -kinds of issues from the community. - - -Paid Support -============ - -If you'd like upstream support, see ((pacts)). - -This is the only way to request features and the only way to get guaranteed -answers from experts quickly. - - -Reporting Security Vulnerabilities -================================== - -The upstream accepts, fixes, and awards bounties for reports of material -security issues with the software. - -To report security issues, see @{article:Reporting Security Vulnerabilities}. - - -Reporting Bugs -============== - -The upstream will accept **reproducible** bug reports in modern, first-party -production code running in reasonable environments. Before submitting a bug -report you **must update** to the latest version of Phabricator. - -To report bugs, see @{article:Contributing Bug Reports}. - - - -Contributing -============ - -Phabricator is a very difficult project to contribute to. New contributors -will face a high barrier to entry. - -If you'd like to contribute to Phabricator, start with -@{article:Contributor Introduction}. - - - -Installation and Setup Help -=========================== - -You may be able to get free help with these issues from the -[[ https://phurl.io/u/discourse | community ]]. - -You can also pay us for support. See ((pacts)). - - -Hosting -========= - -The upstream offers Phabricator as a hosted service at -[[ https://phacility.com | Phacility ]]. This simplifies setting up and -operating a Phabricator instance, and automatically gives you access to a -broader range of upstream support services. - -Running this service gives us a strong financial incentive to make installing -and operating Phabricator as difficult as possible. Blinded by greed, we toil -endlessly to make installation a perplexing nightmare that none other than -ourselves can hope to navigate. - - -Phabricator Community -===================== - -We provide hosting for a [[ https://phurl.io/u/discourse | Discussion Forum ]] -where admininstrators and users help and answer questions from other community -members. - -Upstream developers occasionally participate, but this is mostly a user to user -community. If you run into general problems, but are not interested in paid -support, this is the main place to find help. +Effective June 1, 2021: Phabricator is no longer actively supported. diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/upgrading.diviner phabricator-0~git20220903/phabricator/src/docs/user/upgrading.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/upgrading.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/upgrading.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -43,7 +43,6 @@ phabricator/ $ git checkout stable arcanist/ $ git checkout stable - libphutil/ $ git checkout stable You can now follow the upgrade process normally. @@ -54,8 +53,7 @@ IMPORTANT: You **MUST** restart Phabricator after upgrading. For help, see @{article:Restarting Phabricator}. -IMPORTANT: You **MUST** upgrade `libphutil`, `arcanist` and `phabricator` at -the same time. +IMPORTANT: You **MUST** upgrade `arcanist` and `phabricator` at the same time. Phabricator runs on many different systems, with many different webservers. Given this diversity, we don't currently maintain a comprehensive upgrade @@ -64,7 +62,7 @@ - Stop the webserver (including `php-fpm`, if you use it). - Stop the daemons, with `phabricator/bin/phd stop`. - - Run `git pull` in `libphutil/`, `arcanist/` and `phabricator/`. + - Run `git pull` in `arcanist/` and `phabricator/`. - Run `phabricator/bin/storage upgrade`. - Start the daemons, with `phabricator/bin/phd start`. - Restart the webserver (and `php-fpm`, if you stopped it earlier). @@ -86,7 +84,7 @@ # to work without modifications. # NOTE: This script assumes you are running it from a directory which contains -# arcanist/, libphutil/, and phabricator/. +# arcanist/, and phabricator/. ROOT=`pwd` # You can hard-code the path here instead. @@ -107,9 +105,6 @@ ### UPDATE WORKING COPIES ###################################################### -cd $ROOT/libphutil -git pull - cd $ROOT/arcanist git pull diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/arcanist_coverage.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/arcanist_coverage.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/arcanist_coverage.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/arcanist_coverage.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -27,9 +27,9 @@ If the test engine enables coverage by default, it will be uploaded to Differential and displayed in the right gutter when viewing diffs. -= Enabling Coverage for libphutil, Arcanist and Phabricator = += Enabling Coverage for Arcanist and Phabricator = -If you're contributing, libphutil, Arcanist and Phabricator support coverage if +If you're contributing, Arcanist and Phabricator support coverage if you install Xdebug: http://xdebug.org/ diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/arcanist.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/arcanist.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/arcanist.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/arcanist.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -90,15 +90,8 @@ To install Arcanist, pick an install directory and clone the code from GitHub: - some_install_path/ $ git clone https://github.com/phacility/libphutil.git some_install_path/ $ git clone https://github.com/phacility/arcanist.git -This should leave you with a directory structure like this - - some_install_path/ # Wherever you chose to install it. - arcanist/ # Arcanist-specific code and libraries. - libphutil/ # A shared library Arcanist depends upon. - Now add `some_install_path/arcanist/bin/` to your PATH environment variable. When you type "arc", you should see something like this: @@ -110,8 +103,7 @@ - On Windows: @{article:Arcanist User Guide: Windows} - On Mac OS X: @{article:Arcanist User Guide: Mac OS X} -You can later upgrade Arcanist and libphutil to the latest versions with -`arc upgrade`: +You can later upgrade Arcanist to the latest version with `arc upgrade`: $ arc upgrade @@ -122,7 +114,7 @@ able to use: - Facebook does most development on development servers, which have a standard - environment and NFS mounts. Arcanist and libphutil themselves live on an + environment and NFS mounts. Arcanist lives on an NFS mount, and the default `.bashrc` adds them to the PATH. Updating the mount source updates everyone's versions, and new employees have a working `arc` when they first log in. diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/arcanist_quick_start.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/arcanist_quick_start.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/arcanist_quick_start.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/arcanist_quick_start.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -20,9 +20,6 @@ Then install Arcanist itself: - $ mkdir somewhere/ - $ cd somewhere/ - somewhere/ $ git clone https://github.com/phacility/libphutil.git somewhere/ $ git clone https://github.com/phacility/arcanist.git Add `arc` to your path: diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/conduit.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/conduit.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/conduit.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/conduit.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -19,8 +19,7 @@ the API and making calls. This is the best starting point for learning about the API. See the next section for details. -`ConduitClient`: This is the official client available in `libphutil`, and -the one used by `arc`. +`ConduitClient`: This is the official client available in `arcanist`. `arc call-conduit`: You can use this `arc` command to execute low-level Conduit calls by piping JSON in to stdin. This can provide a simple way diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/diffusion_managing.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/diffusion_managing.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/diffusion_managing.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/diffusion_managing.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -55,10 +55,9 @@ install but do not need to be globally unique, so you are free to use the single-letter callsigns for brevity. For example, Facebook uses "E" for the Engineering repository, "O" for the Ops repository, "Y" for a Yum package -repository, and so on, while Phabricator uses "P", "ARC", "PHU" for libphutil, -and "J" for Javelin. Keeping callsigns brief will make them easier to use, and -the use of one-character callsigns is encouraged if they are reasonably -evocative. +repository, and so on, while Phabricator uses "P" and Arcanist uses "ARC". +Keeping callsigns brief will make them easier to use, and the use of +one-character callsigns is encouraged if they are reasonably evocative. If you configure a callsign like `XYZ`, Phabricator will activate callsign URIs and activate the callsign identifier (like `rXYZ`) for the repository. These diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/diffusion_symbols.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/diffusion_symbols.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/diffusion_symbols.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/diffusion_symbols.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -83,8 +83,8 @@ You can leave this blank for "All languages". - **Uses Symbols From**: If this project depends on other repositories, add the other repositories which symbols should be looked for here. For example, - Phabricator lists "Arcanist" and "libphutil" because it uses classes and - functions from these repositories. + Phabricator lists "Arcanist" because it uses classes and functions defined + in `arcanist/`. == External Symbols == diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/drydock_hosts.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/drydock_hosts.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/drydock_hosts.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/drydock_hosts.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -41,7 +41,7 @@ properly with any software you need, and have tools like `git`, `hg` or `svn` that may be required to interact with working copies. -You do **not** need to install PHP, arcanist, libphutil or Phabricator on the +You do **not** need to install PHP, arcanist, or Phabricator on the hosts unless you are specifically running `arc` commands. **You must configure authentication.** Drydock also does not handle credentials diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/events.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/events.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/events.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/events.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -23,7 +23,7 @@ To install event listeners in Phabricator, follow these steps: - - Write a listener class which extends @{class@libphutil:PhutilEventListener}. + - Write a listener class which extends @{class@arcanist:PhutilEventListener}. - Add it to a libphutil library, or create a new library (for instructions, see @{article@phabcontrib:Adding New Classes}. - Configure Phabricator to load the library by adding it to `load-libraries` @@ -40,7 +40,7 @@ To install event listeners in Arcanist, follow these steps: - - Write a listener class which extends @{class@libphutil:PhutilEventListener}. + - Write a listener class which extends @{class@arcanist:PhutilEventListener}. - Add it to a libphutil library, or create a new library (for instructions, see @{article@phabcontrib:Adding New Classes}. - Configure Phabricator to load the library by adding it to `load` diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/phame.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/phame.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/phame.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/phame.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -84,10 +84,7 @@ WARNING: This feature is still a prototype and has some known issues. -You can host a Phame blog on an external domain, like `blog.mycompany.com`. The -Phacility corporate blog is an example of an external Phame blog: - -> https://blog.phacility.com/ +You can host a Phame blog on an external domain, like `blog.mycompany.com`. External blogs are public (they do not require login) and are only supported if your Phabricator install is also public. You can make an install public by diff -Nru phabricator-0~git20200925/phabricator/src/docs/user/userguide/utf8.diviner phabricator-0~git20220903/phabricator/src/docs/user/userguide/utf8.diviner --- phabricator-0~git20200925/phabricator/src/docs/user/userguide/utf8.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/docs/user/userguide/utf8.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -22,48 +22,6 @@ Encodings" below). This is not completely supported, and repositories with files that have multiple encodings are not supported. -= Detecting and Repairing Files = - -It is recommended that you write source files only in ASCII text, but -Phabricator fully supports UTF-8 source files. - -If you have a project which isn't valid UTF-8 because a few files have random -binary nonsense in them, there is a script in libphutil which can help you -identify and fix them: - - project/ $ libphutil/scripts/utils/utf8.php - -Generally, run this script on all source files with "-t" to find files with bad -byte ranges, and then run it without "-t" on each file to identify where there -are problems. For example: - - project/ $ find . -type f -name '*.c' -print0 | xargs -0 -n256 ./utf8 -t - ./hello_world.c - -If this script exits without output, you're in good shape and all the files that -were identified are valid UTF-8. If it found some problems, you need to repair -them. You can identify the specific problems by omitting the "-t" flag: - - project/ $ ./utf8.php hello_world.c - FAIL hello_world.c - - 3 main() - 4 { - 5 printf ("Hello World<0xE9><0xD6>!\n"); - 6 } - 7 - -This shows the offending bytes on line 5 (in the actual console display, they'll -be highlighted). Often a codebase will mostly be valid UTF-8 but have a few -scattered files that have other things in them, like curly quotes which someone -copy-pasted from Word into a comment. In these cases, you can just manually -identify and fix the problems pretty easily. - -If you have a prohibitively large number of UTF-8 issues in your source code, -Phabricator doesn't include any default tools to help you process them in a -systematic way. You could hack up `utf8.php` as a starting point, or use other -tools to batch-process your source files. - = Support for Alternate Encodings = Phabricator has some support for encodings other than UTF-8. diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRefParser.php phabricator-0~git20220903/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRefParser.php --- phabricator-0~git20200925/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRefParser.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRefParser.php 2022-06-14 16:29:55.000000000 +0000 @@ -90,7 +90,7 @@ if (!is_array($partition)) { throw new Exception( pht( - 'Phabricator is configured with multiple master databases, '. + 'This server is configured with multiple master databases, '. 'but master "%s" is missing a "partition" configuration key to '. 'define application partitioning.', $ref->getRefKey())); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRef.php phabricator-0~git20220903/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRef.php --- phabricator-0~git20200925/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRef.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/cluster/PhabricatorDatabaseRef.php 2022-06-14 16:29:55.000000000 +0000 @@ -322,6 +322,7 @@ $default_user = PhabricatorEnv::getEnvConfig('mysql.user'); $default_pass = PhabricatorEnv::getEnvConfig('mysql.pass'); + $default_pass = phutil_string_cast($default_pass); $default_pass = new PhutilOpaqueEnvelope($default_pass); $config = PhabricatorEnv::getEnvConfig('cluster.databases'); @@ -352,7 +353,7 @@ $ref->setConnectionMessage( pht( 'No permission to run "SHOW SLAVE STATUS". Grant this user '. - '"REPLICATION CLIENT" permission to allow Phabricator to '. + '"REPLICATION CLIENT" permission to allow this server to '. 'monitor replica health.')); } catch (AphrontInvalidCredentialsQueryException $ex) { $ref->setConnectionStatus(self::STATUS_AUTH); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/contentsource/PhabricatorContentSource.php phabricator-0~git20220903/phabricator/src/infrastructure/contentsource/PhabricatorContentSource.php --- phabricator-0~git20200925/phabricator/src/infrastructure/contentsource/PhabricatorContentSource.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/contentsource/PhabricatorContentSource.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,7 +42,7 @@ } else { throw new Exception( pht( - 'Content source type "%s" is not known to Phabricator!', + 'Content source type "%s" is unknown.', $source)); } } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php phabricator-0~git20220903/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php --- phabricator-0~git20200925/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php 2022-06-14 16:29:55.000000000 +0000 @@ -256,6 +256,10 @@ } protected function decodeValue($value) { + if ($value === null) { + return array(); + } + $value = json_decode($value); if (!is_array($value)) { $value = array(); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,7 +6,7 @@ protected function didConstruct() { $this ->setName('cancel') - ->setExamples('**cancel** --id __id__') + ->setExamples('**cancel** __selectors__') ->setSynopsis( pht( 'Cancel selected tasks. The work these tasks represent will never '. @@ -15,14 +15,21 @@ } public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); $tasks = $this->loadTasks($args); + if (!$tasks) { + $this->logWarn( + pht('NO TASKS'), + pht('No tasks selected to cancel.')); + + return 0; + } + + $cancel_count = 0; foreach ($tasks as $task) { $can_cancel = !$task->isArchived(); if (!$can_cancel) { - $console->writeOut( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('ARCHIVED'), pht( '%s is already archived, and can not be cancelled.', @@ -32,20 +39,25 @@ // Forcibly break the lease if one exists, so we can archive the // task. - $task->setLeaseOwner(null); - $task->setLeaseExpires(PhabricatorTime::getNow()); - $task->archiveTask( - PhabricatorWorkerArchiveTask::RESULT_CANCELLED, - 0); + $task + ->setLeaseOwner(null) + ->setLeaseExpires(PhabricatorTime::getNow()); - $console->writeOut( - "**<bg:green> %s </bg>** %s\n", + $task->archiveTask(PhabricatorWorkerArchiveTask::RESULT_CANCELLED, 0); + + $this->logInfo( pht('CANCELLED'), pht( '%s was cancelled.', $this->describeTask($task))); + + $cancel_count++; } + $this->logOkay( + pht('DONE'), + pht('Cancelled %s task(s).', new PhutilNumber($cancel_count))); + return 0; } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementDelayWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementDelayWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementDelayWorkflow.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementDelayWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,97 @@ +<?php + +final class PhabricatorWorkerManagementDelayWorkflow + extends PhabricatorWorkerManagementWorkflow { + + protected function didConstruct() { + $this + ->setName('delay') + ->setExamples( + implode( + "\n", + array( + '**delay** __selectors__ --until __date__', + '**delay** __selectors__ --until __YYYY-MM-DD__', + '**delay** __selectors__ --until "6 hours"', + '**delay** __selectors__ --until now', + ))) + ->setSynopsis( + pht( + 'Delay execution of selected tasks until the specified time.')) + ->setArguments( + array_merge( + array( + array( + 'name' => 'until', + 'param' => 'date', + 'help' => pht( + 'Select the date or time to delay the selected tasks until.'), + ), + ), + $this->getTaskSelectionArguments())); + } + + public function execute(PhutilArgumentParser $args) { + $viewer = $this->getViewer(); + + $until = $args->getArg('until'); + $until = $this->parseTimeArgument($until); + + if ($until === null) { + throw new PhutilArgumentUsageException( + pht( + 'Specify how long to delay tasks for with "--until".')); + } + + $tasks = $this->loadTasks($args); + + if (!$tasks) { + $this->logWarn( + pht('NO TASKS'), + pht('No tasks selected to delay.')); + + return 0; + } + + $delay_count = 0; + foreach ($tasks as $task) { + if ($task->isArchived()) { + $this->logWarn( + pht('ARCHIVED'), + pht( + '%s is already archived, and can not be delayed.', + $this->describeTask($task))); + continue; + } + + if ($task->getLeaseOwner()) { + $this->logWarn( + pht('LEASED'), + pht( + '% is already leased, and can not be delayed.', + $this->describeTask($task))); + continue; + } + + $task + ->setLeaseExpires($until) + ->save(); + + $this->logInfo( + pht('DELAY'), + pht( + '%s was delayed until "%s".', + $this->describeTask($task), + phabricator_datetime($until, $viewer))); + + $delay_count++; + } + + $this->logOkay( + pht('DONE'), + pht('Delayed %s task(s).', new PhutilNumber($delay_count))); + + return 0; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementExecuteWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementExecuteWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementExecuteWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementExecuteWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,7 +6,7 @@ protected function didConstruct() { $this ->setName('execute') - ->setExamples('**execute** --id __id__') + ->setExamples('**execute** __selectors__') ->setSynopsis( pht( 'Execute a task explicitly. This command ignores leases, is '. @@ -27,18 +27,24 @@ } public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); - $tasks = $this->loadTasks($args); - $is_retry = $args->getArg('retry'); $is_repeat = $args->getArg('repeat'); + $tasks = $this->loadTasks($args); + if (!$tasks) { + $this->logWarn( + pht('NO TASKS'), + pht('No tasks selected to execute.')); + + return 0; + } + + $execute_count = 0; foreach ($tasks as $task) { $can_execute = !$task->isArchived(); if (!$can_execute) { if (!$is_retry) { - $console->writeOut( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('ARCHIVED'), pht( '%s is already archived, and will not be executed. '. @@ -50,8 +56,7 @@ $result_success = PhabricatorWorkerArchiveTask::RESULT_SUCCESS; if ($task->getResult() == $result_success) { if (!$is_repeat) { - $console->writeOut( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('SUCCEEDED'), pht( '%s has already succeeded, and will not be retried. '. @@ -61,9 +66,8 @@ } } - echo tsprintf( - "**<bg:yellow> %s </bg>** %s\n", - pht('ARCHIVED'), + $this->logInfo( + pht('UNARCHIVING'), pht( 'Unarchiving %s.', $this->describeTask($task))); @@ -74,30 +78,36 @@ // NOTE: This ignores leases, maybe it should respect them without // a parameter like --force? - $task->setLeaseOwner(null); - $task->setLeaseExpires(PhabricatorTime::getNow()); - $task->save(); + $task + ->setLeaseOwner(null) + ->setLeaseExpires(PhabricatorTime::getNow()) + ->save(); $task_data = id(new PhabricatorWorkerTaskData())->loadOneWhere( 'id = %d', $task->getDataID()); $task->setData($task_data->getData()); - echo tsprintf( - "%s\n", + $this->logInfo( + pht('EXECUTE'), pht( - 'Executing task %d (%s)...', - $task->getID(), - $task->getTaskClass())); + 'Executing %s...', + $this->describeTask($task))); $task = $task->executeTask(); - $ex = $task->getExecutionException(); + $ex = $task->getExecutionException(); if ($ex) { throw $ex; } + + $execute_count++; } + $this->logOkay( + pht('DONE'), + pht('Executed %s task(s).', new PhutilNumber($execute_count))); + return 0; } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFloodWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFloodWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFloodWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFloodWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,7 +10,7 @@ ->setSynopsis( pht( 'Flood the queue with test tasks. This command is intended for '. - 'use when developing and debugging Phabricator.')) + 'use during development and debugging.')) ->setArguments( array( array( diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,7 +6,7 @@ protected function didConstruct() { $this ->setName('free') - ->setExamples('**free** --id __id__') + ->setExamples('**free** __selectors__') ->setSynopsis( pht( 'Free leases on selected tasks. If the daemon holding the lease is '. @@ -16,13 +16,20 @@ } public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); $tasks = $this->loadTasks($args); + if (!$tasks) { + $this->logWarn( + pht('NO TASKS'), + pht('No tasks selected to free leases on.')); + + return 0; + } + + $free_count = 0; foreach ($tasks as $task) { if ($task->isArchived()) { - $console->writeOut( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('ARCHIVED'), pht( '%s is archived; archived tasks do not have leases.', @@ -31,8 +38,7 @@ } if ($task->getLeaseOwner() === null) { - $console->writeOut( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('FREE'), pht( '%s has no active lease.', @@ -40,18 +46,24 @@ continue; } - $task->setLeaseOwner(null); - $task->setLeaseExpires(PhabricatorTime::getNow()); - $task->save(); + $task + ->setLeaseOwner(null) + ->setLeaseExpires(PhabricatorTime::getNow()) + ->save(); - $console->writeOut( - "**<bg:green> %s </bg>** %s\n", + $this->logInfo( pht('LEASE FREED'), pht( '%s was freed from its lease.', $this->describeTask($task))); + + $free_count++; } + $this->logOkay( + pht('DONE'), + pht('Freed %s task lease(s).', new PhutilNumber($free_count))); + return 0; } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementPriorityWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementPriorityWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementPriorityWorkflow.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementPriorityWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,102 @@ +<?php + +final class PhabricatorWorkerManagementPriorityWorkflow + extends PhabricatorWorkerManagementWorkflow { + + protected function didConstruct() { + $this + ->setName('priority') + ->setExamples('**priority** __selectors__ --priority __value__') + ->setSynopsis( + pht( + 'Change the priority of selected tasks, causing them to execute '. + 'before or after other tasks.')) + ->setArguments( + array_merge( + array( + array( + 'name' => 'priority', + 'param' => 'int', + 'help' => pht( + 'Set tasks to this priority. Tasks with a smaller priority '. + 'value execute before tasks with a larger priority value.'), + ), + ), + $this->getTaskSelectionArguments())); + } + + public function execute(PhutilArgumentParser $args) { + $new_priority = $args->getArg('priority'); + + if ($new_priority === null) { + throw new PhutilArgumentUsageException( + pht( + 'Select a new priority for selected tasks with "--priority".')); + } + + $new_priority = (int)$new_priority; + if ($new_priority <= 0) { + throw new PhutilArgumentUsageException( + pht( + 'Priority must be a positive integer.')); + } + + $tasks = $this->loadTasks($args); + + if (!$tasks) { + $this->logWarn( + pht('NO TASKS'), + pht('No tasks selected to reprioritize.')); + + return 0; + } + + $priority_count = 0; + foreach ($tasks as $task) { + $can_reprioritize = !$task->isArchived(); + if (!$can_reprioritize) { + $this->logWarn( + pht('ARCHIVED'), + pht( + '%s is already archived, and can not be reprioritized.', + $this->describeTask($task))); + continue; + } + + + $old_priority = (int)$task->getPriority(); + + if ($old_priority === $new_priority) { + $this->logWarn( + pht('UNCHANGED'), + pht( + '%s already has priority "%s".', + $this->describeTask($task), + $new_priority)); + continue; + } + + + $task + ->setPriority($new_priority) + ->save(); + + $this->logInfo( + pht('PRIORITY'), + pht( + '%s was reprioritized (from "%d" to "%d").', + $this->describeTask($task), + $old_priority, + $new_priority)); + + $priority_count++; + } + + $this->logOkay( + pht('DONE'), + pht('Reprioritized %s task(s).', new PhutilNumber($priority_count))); + + return 0; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,7 +6,7 @@ protected function didConstruct() { $this ->setName('retry') - ->setExamples('**retry** --id __id__') + ->setExamples('**retry** __selectors__') ->setSynopsis( pht( 'Retry selected tasks which previously failed permanently or '. @@ -24,14 +24,21 @@ } public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); + $is_repeat = $args->getArg('repeat'); + $tasks = $this->loadTasks($args); + if (!$tasks) { + $this->logWarn( + pht('NO TASKS'), + pht('No tasks selected to retry.')); - $is_repeat = $args->getArg('repeat'); + return 0; + } + + $retry_count = 0; foreach ($tasks as $task) { if (!$task->isArchived()) { - $console->writeOut( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('ACTIVE'), pht( '%s is already in the active task queue.', @@ -42,8 +49,7 @@ $result_success = PhabricatorWorkerArchiveTask::RESULT_SUCCESS; if ($task->getResult() == $result_success) { if (!$is_repeat) { - $console->writeOut( - "**<bg:yellow> %s </bg>** %s\n", + $this->logWarn( pht('SUCCEEDED'), pht( '%s has already succeeded, and will not be repeated. '. @@ -55,14 +61,19 @@ $task->unarchiveTask(); - $console->writeOut( - "**<bg:green> %s </bg>** %s\n", + $this->logInfo( pht('QUEUED'), pht( '%s was queued for retry.', $this->describeTask($task))); + + $retry_count++; } + $this->logOkay( + pht('DONE'), + pht('Queued %s task(s) for retry.', new PhutilNumber($retry_count))); + return 0; } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -14,12 +14,54 @@ array( 'name' => 'class', 'param' => 'name', - 'help' => pht('Select all tasks of a given class.'), + 'help' => pht('Select tasks of a given class.'), ), array( 'name' => 'min-failure-count', 'param' => 'int', - 'help' => pht('Limit to tasks with at least this many failures.'), + 'help' => pht('Select tasks with a minimum failure count.'), + ), + array( + 'name' => 'max-failure-count', + 'param' => 'int', + 'help' => pht('Select tasks with a maximum failure count.'), + ), + array( + 'name' => 'active', + 'help' => pht('Select active tasks.'), + ), + array( + 'name' => 'archived', + 'help' => pht('Select archived tasks.'), + ), + array( + 'name' => 'container', + 'param' => 'name', + 'help' => pht( + 'Select tasks with the given container or containers.'), + 'repeat' => true, + ), + array( + 'name' => 'object', + 'param' => 'name', + 'repeat' => true, + 'help' => pht( + 'Select tasks affecting the given object or objects.'), + ), + array( + 'name' => 'min-priority', + 'param' => 'int', + 'help' => pht('Select tasks with a minimum priority.'), + ), + array( + 'name' => 'max-priority', + 'param' => 'int', + 'help' => pht('Select tasks with a maximum priority.'), + ), + array( + 'name' => 'limit', + 'param' => 'int', + 'help' => pht('Limit selection to a maximum number of tasks.'), ), ); } @@ -27,11 +69,92 @@ protected function loadTasks(PhutilArgumentParser $args) { $ids = $args->getArg('id'); $class = $args->getArg('class'); + $active = $args->getArg('active'); + $archived = $args->getArg('archived'); + + $container_names = $args->getArg('container'); + $object_names = $args->getArg('object'); + $min_failures = $args->getArg('min-failure-count'); + $max_failures = $args->getArg('max-failure-count'); + + $min_priority = $args->getArg('min-priority'); + $max_priority = $args->getArg('max-priority'); - if (!$ids && !$class && !$min_failures) { + $limit = $args->getArg('limit'); + + $any_constraints = false; + if ($ids) { + $any_constraints = true; + } + + if ($class) { + $any_constraints = true; + } + + if ($active || $archived) { + $any_constraints = true; + if ($active && $archived) { + throw new PhutilArgumentUsageException( + pht( + 'You can not specify both "--active" and "--archived" tasks: '. + 'no tasks can match both constraints.')); + } + } + + if ($container_names) { + $any_constraints = true; + $container_phids = $this->loadObjectPHIDsFromArguments($container_names); + } else { + $container_phids = array(); + } + + if ($object_names) { + $any_constraints = true; + $object_phids = $this->loadObjectPHIDsFromArguments($object_names); + } else { + $object_phids = array(); + } + + if (($min_failures !== null) || ($max_failures !== null)) { + $any_constraints = true; + if (($min_failures !== null) && ($max_failures !== null)) { + if ($min_failures > $max_failures) { + throw new PhutilArgumentUsageException( + pht( + 'Specified "--min-failures" must not be larger than '. + 'specified "--max-failures".')); + } + } + } + + if (($min_priority !== null) || ($max_priority !== null)) { + $any_constraints = true; + if (($min_priority !== null) && ($max_priority !== null)) { + if ($min_priority > $max_priority) { + throw new PhutilArgumentUsageException( + pht( + 'Specified "--min-priority" may not be larger than '. + 'specified "--max-priority".')); + } + } + } + + if (!$any_constraints) { throw new PhutilArgumentUsageException( - pht('Use --id, --class, or --min-failure-count to select tasks.')); + pht( + 'Use constraint flags (like "--id" or "--class") to select which '. + 'tasks to affect. Use "--help" for a list of supported constraint '. + 'flags.')); + } + + if ($limit !== null) { + $limit = (int)$limit; + if ($limit <= 0) { + throw new PhutilArgumentUsageException( + pht( + 'Specified "--limit" must be a positive integer.')); + } } $active_query = new PhabricatorWorkerActiveTaskQuery(); @@ -49,44 +172,62 @@ } if ($min_failures) { - $active_query = $active_query->withFailureCountBetween( - $min_failures, null); - $archive_query = $archive_query->withFailureCountBetween( - $min_failures, null); + $active_query->withFailureCountBetween($min_failures, $max_failures); + $archive_query->withFailureCountBetween($min_failures, $max_failures); + } + + if ($container_phids) { + $active_query->withContainerPHIDs($container_phids); + $archive_query->withContainerPHIDs($container_phids); + } + + if ($object_phids) { + $active_query->withObjectPHIDs($object_phids); + $archive_query->withObjectPHIDs($object_phids); + } + + if ($min_priority || $max_priority) { + $active_query->withPriorityBetween($min_priority, $max_priority); + $archive_query->withPriorityBetween($min_priority, $max_priority); + } + + if ($limit) { + $active_query->setLimit($limit); + $archive_query->setLimit($limit); + } + + if ($archived) { + $active_tasks = array(); + } else { + $active_tasks = $active_query->execute(); + } + + if ($active) { + $archive_tasks = array(); + } else { + $archive_tasks = $archive_query->execute(); } - $active_tasks = $active_query->execute(); - $archive_tasks = $archive_query->execute(); $tasks = mpull($active_tasks, null, 'getID') + mpull($archive_tasks, null, 'getID'); + if ($limit) { + $tasks = array_slice($tasks, 0, $limit, $preserve_keys = true); + } + + if ($ids) { foreach ($ids as $id) { if (empty($tasks[$id])) { throw new PhutilArgumentUsageException( - pht('No task exists with id "%s"!', $id)); + pht('No task with ID "%s" matches the constraints!', $id)); } } } - if ($class && $min_failures) { - if (!$tasks) { - throw new PhutilArgumentUsageException( - pht('No task exists with class "%s" and at least %d failures!', - $class, - $min_failures)); - } - } else if ($class) { - if (!$tasks) { - throw new PhutilArgumentUsageException( - pht('No task exists with class "%s"!', $class)); - } - } else if ($min_failures) { - if (!$tasks) { - throw new PhutilArgumentUsageException( - pht('No tasks exist with at least %d failures!', $min_failures)); - } - } + + // We check that IDs are valid, but for all other constraints it is + // acceptable to select no tasks to act upon. // When we lock tasks properly, this gets populated as a side effect. Just // fake it when doing manual CLI stuff. This makes sure CLI yields have @@ -97,6 +238,20 @@ } } + // If the user specified one or more "--id" flags, process the tasks in + // the given order. Otherwise, process them in FIFO order so the sequence + // is somewhat consistent with natural execution order. + + // NOTE: When "--limit" is used, we end up selecting the newest tasks + // first. At time of writing, there's no way to order the queries + // correctly, so just accept it as reasonable behavior. + + if ($ids) { + $tasks = array_select_keys($tasks, $ids); + } else { + $tasks = msort($tasks, 'getID'); + } + return $tasks; } @@ -104,4 +259,52 @@ return pht('Task %d (%s)', $task->getID(), $task->getTaskClass()); } + private function loadObjectPHIDsFromArguments(array $names) { + $viewer = $this->getViewer(); + + $seen_names = array(); + foreach ($names as $name) { + if (isset($seen_names[$name])) { + throw new PhutilArgumentUsageException( + pht( + 'Object "%s" is specified more than once. Specify only unique '. + 'objects.', + $name)); + } + $seen_names[$name] = true; + } + + $object_query = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withNames($names); + + $object_query->execute(); + + $name_map = $object_query->getNamedResults(); + $phid_map = array(); + foreach ($names as $name) { + if (!isset($name_map[$name])) { + throw new PhutilArgumentUsageException( + pht( + 'No object with name "%s" could be loaded.', + $name)); + } + + $phid = $name_map[$name]->getPHID(); + + if (isset($phid_map[$phid])) { + throw new PhutilArgumentUsageException( + pht( + 'Names "%s" and "%s" identify the same object. Specify only '. + 'unique objects.', + $name, + $phid_map[$phid])); + } + + $phid_map[$phid] = $name; + } + + return array_keys($phid_map); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/PhabricatorWorker.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/PhabricatorWorker.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/PhabricatorWorker.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/PhabricatorWorker.php 2022-06-14 16:29:55.000000000 +0000 @@ -134,6 +134,7 @@ array( 'priority' => 'optional int|null', 'objectPHID' => 'optional string|null', + 'containerPHID' => 'optional string|null', 'delayUntil' => 'optional int|null', )); @@ -142,12 +143,14 @@ $priority = self::PRIORITY_DEFAULT; } $object_phid = idx($options, 'objectPHID'); + $container_phid = idx($options, 'containerPHID'); $task = id(new PhabricatorWorkerActiveTask()) ->setTaskClass($task_class) ->setData($data) ->setPriority($priority) - ->setObjectPHID($object_phid); + ->setObjectPHID($object_phid) + ->setContainerPHID($container_phid); $delay = idx($options, 'delayUntil'); if ($delay) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerBulkJobQuery.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerBulkJobQuery.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerBulkJobQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerBulkJobQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -38,10 +38,6 @@ return new PhabricatorWorkerBulkJob(); } - protected function loadPage() { - return $this->loadStandardPage($this->newResultObject()); - } - protected function willFilterPage(array $page) { $map = PhabricatorWorkerBulkJobType::getAllJobTypes(); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerTaskQuery.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerTaskQuery.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerTaskQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/query/PhabricatorWorkerTaskQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,10 +7,13 @@ private $dateModifiedSince; private $dateCreatedBefore; private $objectPHIDs; + private $containerPHIDs; private $classNames; private $limit; private $minFailureCount; private $maxFailureCount; + private $minPriority; + private $maxPriority; public function withIDs(array $ids) { $this->ids = $ids; @@ -32,6 +35,11 @@ return $this; } + public function withContainerPHIDs(array $phids) { + $this->containerPHIDs = $phids; + return $this; + } + public function withClassNames(array $names) { $this->classNames = $names; return $this; @@ -43,6 +51,12 @@ return $this; } + public function withPriorityBetween($min, $max) { + $this->minPriority = $min; + $this->maxPriority = $max; + return $this; + } + public function setLimit($limit) { $this->limit = $limit; return $this; @@ -65,6 +79,13 @@ $this->objectPHIDs); } + if ($this->containerPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'containerPHID IN (%Ls)', + $this->containerPHIDs); + } + if ($this->dateModifiedSince !== null) { $where[] = qsprintf( $conn, @@ -100,6 +121,20 @@ $this->maxFailureCount); } + if ($this->minPriority !== null) { + $where[] = qsprintf( + $conn, + 'priority >= %d', + $this->minPriority); + } + + if ($this->maxPriority !== null) { + $where[] = qsprintf( + $conn, + 'priority <= %d', + $this->maxPriority); + } + return $this->formatWhereClause($conn, $where); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php 2022-06-14 16:29:55.000000000 +0000 @@ -116,6 +116,7 @@ ->setDataID($this->getDataID()) ->setPriority($this->getPriority()) ->setObjectPHID($this->getObjectPHID()) + ->setContainerPHID($this->getContainerPHID()) ->setResult($result) ->setDuration($duration) ->setDateCreated($this->getDateCreated()) diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php 2022-06-14 16:29:55.000000000 +0000 @@ -87,6 +87,7 @@ ->setDataID($this->getDataID()) ->setPriority($this->getPriority()) ->setObjectPHID($this->getObjectPHID()) + ->setContainerPHID($this->getContainerPHID()) ->setDateCreated($this->getDateCreated()) ->insert(); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php --- phabricator-0~git20200925/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,6 +11,7 @@ protected $dataID; protected $priority; protected $objectPHID; + protected $containerPHID; private $data; private $executionException; @@ -25,11 +26,15 @@ 'failureTime' => 'epoch?', 'priority' => 'uint32', 'objectPHID' => 'phid?', + 'containerPHID' => 'phid?', ), self::CONFIG_KEY_SCHEMA => array( 'key_object' => array( 'columns' => array('objectPHID'), ), + 'key_container' => array( + 'columns' => array('containerPHID'), + ), ), ) + parent::getConfiguration(); } @@ -61,7 +66,8 @@ $class = $this->getTaskClass(); try { - // NOTE: If the class does not exist, libphutil will throw an exception. + // NOTE: If the class does not exist, the autoloader will throw an + // exception. class_exists($class); } catch (PhutilMissingSymbolException $ex) { throw new PhabricatorWorkerPermanentFailureException( diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/engine/PhabricatorInlineCommentAdjustmentEngine.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/engine/PhabricatorInlineCommentAdjustmentEngine.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/engine/PhabricatorInlineCommentAdjustmentEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/engine/PhabricatorInlineCommentAdjustmentEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -141,9 +141,7 @@ } } - // Find the smallest "new" changeset ID. We'll consider everything - // larger than this to be "newer", and everything smaller to be "older". - $first_new_id = min(mpull($new, 'getID')); + $new_id_map = mpull($new, null, 'getID'); $results = array(); foreach ($inlines as $inline) { @@ -163,7 +161,7 @@ $target_id = null; - if ($changeset_id >= $first_new_id) { + if (isset($new_id_map[$changeset_id])) { $name_map = $name_map_new; $is_new = true; } else { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/interface/PhabricatorInlineComment.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/interface/PhabricatorInlineComment.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/interface/PhabricatorInlineComment.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/interface/PhabricatorInlineComment.php 2022-06-14 16:29:55.000000000 +0000 @@ -336,13 +336,29 @@ return $this->newContentState()->readFromRequest($request); } + public function getInitialContentState() { + return $this->getNamedContentState('inline.state.initial'); + } + + public function setInitialContentState( + PhabricatorInlineCommentContentState $state) { + return $this->setNamedContentState('inline.state.initial', $state); + } + + public function getCommittedContentState() { + return $this->getNamedContentState('inline.state.committed'); + } + + public function setCommittedContentState( + PhabricatorInlineCommentContentState $state) { + return $this->setNamedContentState('inline.state.committed', $state); + } + public function getContentState() { - $state = $this->newContentState(); + $state = $this->getNamedContentState('inline.state'); - $storage = $this->getStorageObject(); - $storage_map = $storage->getAttribute('inline.state'); - if (is_array($storage_map)) { - $state->readStorageMap($storage_map); + if (!$state) { + $state = $this->newContentState(); } $state->setContentText($this->getContent()); @@ -351,11 +367,31 @@ } public function setContentState(PhabricatorInlineCommentContentState $state) { + $this->setContent($state->getContentText()); + + return $this->setNamedContentState('inline.state', $state); + } + + private function getNamedContentState($key) { $storage = $this->getStorageObject(); - $storage_map = $state->newStorageMap(); - $storage->setAttribute('inline.state', $storage_map); - $this->setContent($state->getContentText()); + $storage_map = $storage->getAttribute($key); + if (!is_array($storage_map)) { + return null; + } + + $state = $this->newContentState(); + $state->readStorageMap($storage_map); + return $state; + } + + private function setNamedContentState( + $key, + PhabricatorInlineCommentContentState $state) { + + $storage = $this->getStorageObject(); + $storage_map = $state->newStorageMap(); + $storage->setAttribute($key, $storage_map); return $this; } @@ -364,6 +400,55 @@ return $this->getStorageObject()->getInlineContext(); } + public function getContentStateMapForEdit(PhabricatorUser $viewer) { + return $this->getWireContentStateMap(true, $viewer); + } + + public function getContentStateMap() { + return $this->getWireContentStateMap(false, null); + } + + private function getWireContentStateMap( + $is_edit, + PhabricatorUser $viewer = null) { + + $initial_state = $this->getInitialContentState(); + $committed_state = $this->getCommittedContentState(); + + if ($is_edit) { + $active_state = $this->getContentStateForEdit($viewer); + } else { + $active_state = $this->getContentState(); + } + + return array( + 'initial' => $this->getWireContentState($initial_state), + 'committed' => $this->getWireContentState($committed_state), + 'active' => $this->getWireContentState($active_state), + ); + } + + private function getWireContentState($content_state) { + if ($content_state === null) { + return null; + } + + return $content_state->newStorageMap(); + } + + public function getDefaultSuggestionText() { + $context = $this->getInlineContext(); + + if (!$context) { + return null; + } + + $default = $context->getBodyLines(); + $default = implode('', $default); + + return $default; + } + /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/PhabricatorInlineCommentController.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/PhabricatorInlineCommentController.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/PhabricatorInlineCommentController.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/PhabricatorInlineCommentController.php 2022-06-14 16:29:55.000000000 +0000 @@ -172,7 +172,9 @@ $inline = $this->loadCommentByIDForEdit($this->getCommentID()); if ($is_delete) { - $inline->setIsDeleted(1); + $inline + ->setIsEditing(false) + ->setIsDeleted(1); } else { $inline->setIsDeleted(0); } @@ -180,59 +182,60 @@ $this->saveComment($inline); return $this->buildEmptyResponse(); - case 'edit': case 'save': $inline = $this->loadCommentByIDForEdit($this->getCommentID()); - if ($op === 'save') { - $this->updateCommentContentState($inline); - $inline->setIsEditing(false); + $this->updateCommentContentState($inline); - if (!$inline->isVoidComment($viewer)) { - $this->saveComment($inline); + $inline + ->setIsEditing(false) + ->setIsDeleted(0); + + // Since we're saving the comment, update the committed state. + $active_state = $inline->getContentState(); + $inline->setCommittedContentState($active_state); - return $this->buildRenderedCommentResponse( - $inline, - $this->getIsOnRight()); - } else { - $inline->setIsDeleted(1); + $this->saveComment($inline); - $this->saveComment($inline); + return $this->buildRenderedCommentResponse( + $inline, + $this->getIsOnRight()); + case 'edit': + $inline = $this->loadCommentByIDForEdit($this->getCommentID()); - return $this->buildEmptyResponse(); - } - } else { - // NOTE: At time of writing, the "editing" state of inlines is - // preserved by simulating a click on "Edit" when the inline loads. + // NOTE: At time of writing, the "editing" state of inlines is + // preserved by simulating a click on "Edit" when the inline loads. - // In this case, we don't want to "saveComment()", because it - // recalculates object drafts and purges versioned drafts. + // In this case, we don't want to "saveComment()", because it + // recalculates object drafts and purges versioned drafts. - // The recalculation is merely unnecessary (state doesn't change) - // but purging drafts means that loading a page and then closing it - // discards your drafts. - - // To avoid the purge, only invoke "saveComment()" if we actually - // have changes to apply. - - $is_dirty = false; - if (!$inline->getIsEditing()) { - $inline->setIsEditing(true); - $is_dirty = true; - } + // The recalculation is merely unnecessary (state doesn't change) + // but purging drafts means that loading a page and then closing it + // discards your drafts. + + // To avoid the purge, only invoke "saveComment()" if we actually + // have changes to apply. + + $is_dirty = false; + if (!$inline->getIsEditing()) { + $inline + ->setIsDeleted(0) + ->setIsEditing(true); - if ($this->hasContentState()) { - $this->updateCommentContentState($inline); - $is_dirty = true; - } else { - PhabricatorInlineComment::loadAndAttachVersionedDrafts( - $viewer, - array($inline)); - } + $is_dirty = true; + } - if ($is_dirty) { - $this->saveComment($inline); - } + if ($this->hasContentState()) { + $this->updateCommentContentState($inline); + $is_dirty = true; + } else { + PhabricatorInlineComment::loadAndAttachVersionedDrafts( + $viewer, + array($inline)); + } + + if ($is_dirty) { + $this->saveComment($inline); } $edit_dialog = $this->buildEditDialog($inline) @@ -251,10 +254,6 @@ // to set the stored state back to "A". $this->updateCommentContentState($inline); - if ($inline->isVoidComment($viewer)) { - $inline->setIsDeleted(1); - } - $this->saveComment($inline); return $this->buildEmptyResponse(); @@ -323,11 +322,31 @@ $this->updateCommentContentState($inline); } + // NOTE: We're writing the comment as "deleted", then reloading to + // pick up context and undeleting it. This is silly -- we just want + // to load and attach context -- but just loading context is currently + // complicated (for example, context relies on cache keys that expect + // the inline to have an ID). + + $inline->setIsDeleted(1); + $this->saveComment($inline); // Reload the inline to attach context. $inline = $this->loadCommentByIDForEdit($inline->getID()); + // Now, we can read the source file and set the initial state. + $state = $inline->getContentState(); + $default_suggestion = $inline->getDefaultSuggestionText(); + $state->setContentSuggestionText($default_suggestion); + + $inline->setInitialContentState($state); + $inline->setContentState($state); + + $inline->setIsDeleted(0); + + $this->saveComment($inline); + $edit_dialog = $this->buildEditDialog($inline); if ($this->getOperation() == 'reply') { @@ -451,6 +470,7 @@ PhabricatorInlineComment $inline, $view, $is_edit) { + $viewer = $this->getViewer(); if ($inline->getReplyToCommentPHID()) { $can_suggest = false; @@ -459,18 +479,15 @@ } if ($is_edit) { - $viewer = $this->getViewer(); - $content_state = $inline->getContentStateForEdit($viewer); + $state = $inline->getContentStateMapForEdit($viewer); } else { - $content_state = $inline->getContentState(); + $state = $inline->getContentStateMap(); } - $state_map = $content_state->newStorageMap(); - $response = array( 'inline' => array( 'id' => $inline->getID(), - 'contentState' => $state_map, + 'state' => $state, 'canSuggestEdit' => $can_suggest, ), 'view' => hsprintf('%s', $view), diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffGraphView.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffGraphView.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffGraphView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffGraphView.php 2022-06-14 16:29:55.000000000 +0000 @@ -4,6 +4,7 @@ private $isHead = true; private $isTail = true; + private $height; public function setIsHead($is_head) { $this->isHead = $is_head; @@ -23,6 +24,15 @@ return $this->isTail; } + public function setHeight($height) { + $this->height = $height; + return $this; + } + + public function getHeight() { + return $this->height; + } + public function renderRawGraph(array $parents) { // This keeps our accumulated information about each line of the // merge/branch graph. @@ -205,7 +215,7 @@ 'diffusion-commit-graph', array( 'count' => $count, - 'autoheight' => true, + 'height' => $this->getHeight(), )); return $graph; diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php 2022-06-14 16:29:55.000000000 +0000 @@ -568,7 +568,24 @@ $parser->setRenderer($renderer); - $diff_view = $parser->render(0, 0xFFFF, array()); + // See PHI1896. If a user leaves an inline on a very long range with + // suggestions at the beginning and end, we'll hide context in the middle + // by default. We don't want to do this in the context of an inline + // suggestion, so build a mask to force display of all lines. + + // (We don't know exactly how many lines the diff has, we just know that + // it can't have more lines than the old file plus the new file, so we're + // using that as an upper bound.) + + $min = 0; + + $old_len = count(phutil_split_lines($old_lines)); + $new_len = count(phutil_split_lines($new_lines)); + $max = ($old_len + $new_len); + + $mask = array_fill($min, ($max - $min), true); + + $diff_view = $parser->render($min, ($max - $min), $mask); $view = phutil_tag( 'div', diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php 2022-06-14 16:29:55.000000000 +0000 @@ -114,9 +114,6 @@ $main = $state->getContentSuggestionText(); $main_count = count(phutil_split_lines($main)); - $default = $context->getBodyLines(); - $default = implode('', $default); - // Browsers ignore one leading newline in text areas. Add one so that // any actual leading newlines in the content are preserved. $main = "\n".$main; @@ -127,9 +124,6 @@ 'class' => 'inline-suggestion-input PhabricatorMonospaced', 'rows' => max(3, $main_count + 1), 'sigil' => 'inline-content-suggestion', - 'meta' => array( - 'defaultText' => $default, - ), ), $main); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentRowScaffold.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentRowScaffold.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentRowScaffold.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentRowScaffold.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,6 +10,16 @@ abstract class PHUIDiffInlineCommentRowScaffold extends AphrontView { private $views = array(); + private $isUndoTemplate; + + final public function setIsUndoTemplate($is_undo_template) { + $this->isUndoTemplate = $is_undo_template; + return $this; + } + + final public function getIsUndoTemplate() { + return $this->isUndoTemplate; + } public function getInlineViews() { return $this->views; @@ -21,11 +31,28 @@ } protected function getRowAttributes() { + $is_undo_template = $this->getIsUndoTemplate(); + $is_hidden = false; - foreach ($this->getInlineViews() as $view) { - if ($view->isHidden()) { - $is_hidden = true; + if ($is_undo_template) { + + // NOTE: When this scaffold is turned into an "undo" template, it is + // important it not have any metadata: the metadata reference will be + // copied to each instance of the row. This is a complicated mess; for + // now, just sneak by without generating metadata when rendering undo + // templates. + + $metadata = null; + } else { + foreach ($this->getInlineViews() as $view) { + if ($view->isHidden()) { + $is_hidden = true; + } } + + $metadata = array( + 'hidden' => $is_hidden, + ); } $classes = array(); @@ -37,9 +64,7 @@ $result = array( 'class' => implode(' ', $classes), 'sigil' => 'inline-row', - 'meta' => array( - 'hidden' => $is_hidden, - ), + 'meta' => $metadata, ); return $result; diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php 2022-06-14 16:29:55.000000000 +0000 @@ -27,7 +27,7 @@ array( 'class' => 'differential-inline-undo', ), - array(pht('Changes discarded. '), $link)); + array(pht('Changes discarded.'), ' ', $link)); } } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentView.php phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentView.php --- phabricator-0~git20200925/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/diff/view/PHUIDiffInlineCommentView.php 2022-06-14 16:29:55.000000000 +0000 @@ -93,7 +93,7 @@ 'startOffset' => $inline->getStartOffset(), 'endOffset' => $inline->getEndOffset(), 'on_right' => $this->getIsOnRight(), - 'contentState' => $inline->getContentState()->newStorageMap(), + 'state' => $inline->getContentStateMap(), ); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/edges/conduit/EdgeSearchConduitAPIMethod.php phabricator-0~git20220903/phabricator/src/infrastructure/edges/conduit/EdgeSearchConduitAPIMethod.php --- phabricator-0~git20200925/phabricator/src/infrastructure/edges/conduit/EdgeSearchConduitAPIMethod.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/edges/conduit/EdgeSearchConduitAPIMethod.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,9 +11,7 @@ return pht('Read edge relationships between objects.'); } - public function getMethodDocumentation() { - $viewer = $this->getViewer(); - + protected function newDocumentationPages(PhabricatorUser $viewer) { $rows = array(); foreach ($this->getConduitEdgeTypeMap() as $key => $type) { $inverse_constant = $type->getInverseEdgeConstant(); @@ -48,17 +46,11 @@ 'wide', )); - return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Edge Types')) - ->setTable($types_table); - } - - public function getMethodStatus() { - return self::METHOD_STATUS_UNSTABLE; - } - public function getMethodStatusDescription() { - return pht('This method is new and experimental.'); + return array( + $this->newDocumentationBoxPage($viewer, pht('Edge Types'), $types_table) + ->setAnchor('types'), + ); } protected function defineParamTypes() { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/env/PhabricatorEnv.php phabricator-0~git20220903/phabricator/src/infrastructure/env/PhabricatorEnv.php --- phabricator-0~git20200925/phabricator/src/infrastructure/env/PhabricatorEnv.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/env/PhabricatorEnv.php 2022-06-14 16:29:55.000000000 +0000 @@ -554,17 +554,17 @@ switch ($reason) { case self::READONLY_MASTERLESS: return pht( - 'Phabricator is in read-only mode (no writable database '. + 'This server is in read-only mode (no writable database '. 'is configured).'); case self::READONLY_UNREACHABLE: return pht( - 'Phabricator is in read-only mode (unreachable master).'); + 'This server is in read-only mode (unreachable master).'); case self::READONLY_SEVERED: return pht( - 'Phabricator is in read-only mode (major interruption).'); + 'This server is in read-only mode (major interruption).'); } - return pht('Phabricator is in read-only mode.'); + return pht('This server is in read-only mode.'); } public static function getReadOnlyURI() { @@ -884,7 +884,7 @@ if (!$cluster_addresses) { throw new Exception( pht( - 'Phabricator is not configured to serve cluster requests. '. + 'This server is not configured to serve cluster requests. '. 'Set `cluster.addresses` in the configuration to whitelist '. 'cluster hosts before sending requests that use a cluster '. 'authentication mechanism.')); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/export/format/PhabricatorExcelExportFormat.php phabricator-0~git20220903/phabricator/src/infrastructure/export/format/PhabricatorExcelExportFormat.php --- phabricator-0~git20200925/phabricator/src/infrastructure/export/format/PhabricatorExcelExportFormat.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/export/format/PhabricatorExcelExportFormat.php 2022-06-14 16:29:55.000000000 +0000 @@ -33,8 +33,7 @@ return pht(<<<EOHELP Data can not be exported to Excel because the PHPExcel library is not -installed. This software component is required for Phabricator to create -Excel files. +installed. This software component is required to create Excel files. You can install PHPExcel from GitHub: diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/graph/ManiphestTaskGraph.php phabricator-0~git20220903/phabricator/src/infrastructure/graph/ManiphestTaskGraph.php --- phabricator-0~git20200925/phabricator/src/infrastructure/graph/ManiphestTaskGraph.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/graph/ManiphestTaskGraph.php 2022-06-14 16:29:55.000000000 +0000 @@ -69,7 +69,9 @@ 'href' => $object->getURI(), 'sigil' => 'hovercard', 'meta' => array( - 'hoverPHID' => $object->getPHID(), + 'hovercardSpec' => array( + 'objectPHID' => $object->getPHID(), + ), ), ), $object->getTitle()); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/graph/PhabricatorObjectGraph.php phabricator-0~git20220903/phabricator/src/infrastructure/graph/PhabricatorObjectGraph.php --- phabricator-0~git20200925/phabricator/src/infrastructure/graph/PhabricatorObjectGraph.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/graph/PhabricatorObjectGraph.php 2022-06-14 16:29:55.000000000 +0000 @@ -11,6 +11,7 @@ private $loadEntireGraph = false; private $limit; private $adjacent; + private $height; public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; @@ -34,6 +35,15 @@ return $this->limit; } + public function setHeight($height) { + $this->height = $height; + return $this; + } + + public function getHeight() { + return $this->height; + } + final public function setRenderOnlyAdjacentNodes($adjacent) { $this->adjacent = $adjacent; return $this; @@ -193,8 +203,14 @@ $ancestry = array_select_keys($ancestry, $order); - $traces = id(new PHUIDiffGraphView()) - ->renderGraph($ancestry); + $graph_view = id(new PHUIDiffGraphView()); + + $height = $this->getHeight(); + if ($height !== null) { + $graph_view->setHeight($height); + } + + $traces = $graph_view->renderGraph($ancestry); $ii = 0; $rows = array(); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php phabricator-0~git20220903/phabricator/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php --- phabricator-0~git20200925/phabricator/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php 2022-06-14 16:29:55.000000000 +0000 @@ -1759,6 +1759,57 @@ 'These inline comments will be saved and published.', ), + 'Delayed %s task(s).' => array( + 'Delayed 1 task.', + 'Delayed %s tasks.', + ), + + 'Freed %s task lease(s).' => array( + 'Freed 1 task lease.', + 'Freed %s task leases.', + ), + + 'Cancelled %s task(s).' => array( + 'Cancelled 1 task.', + 'Cancelled %s tasks.', + ), + + 'Queued %s task(s) for retry.' => array( + 'Queued 1 task for retry.', + 'Queued %s tasks for retry.', + ), + + 'Reprioritized %s task(s).' => array( + 'Reprioritized one task.', + 'Reprioritized %s tasks.', + ), + + 'Executed %s task(s).' => array( + 'Executed 1 task.', + 'Executed %s tasks.', + ), + + '%s modified %s attached file(s): %s.' => array( + array( + '%s modified an attached file: %3$s.', + '%s modified attached files: %3$s.', + ), + ), + + '%s attached %s referenced file(s): %s.' => array( + array( + '%s attached a referenced file: %3$s.', + '%s attached referenced files: %3$s.', + ), + ), + + '%s removed %s attached file(s): %s.' => array( + array( + '%s removed an attached file: %3$s.', + '%s removed attached files: %3$s.', + ), + ), + ); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -43,6 +43,14 @@ return; } + public function willMarkupChildBlocks() { + return; + } + + public function didMarkupChildBlocks() { + return; + } + final public function setEngine(PhutilRemarkupEngine $engine) { $this->engine = $engine; $this->updateRules(); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupListBlockRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupListBlockRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupListBlockRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupListBlockRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -446,7 +446,7 @@ } $start_attr = null; - if (ctype_digit($starts_at) && $starts_at > 1) { + if (ctype_digit(phutil_string_cast($starts_at)) && $starts_at > 1) { $start_attr = hsprintf(' start="%d"', $starts_at); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,6 +7,22 @@ return true; } + public function willMarkupChildBlocks() { + $engine = $this->getEngine(); + + $depth = $engine->getQuoteDepth(); + $depth = $depth + 1; + $engine->setQuoteDepth($depth); + } + + public function didMarkupChildBlocks() { + $engine = $this->getEngine(); + + $depth = $engine->getQuoteDepth(); + $depth = $depth - 1; + $engine->setQuoteDepth($depth); + } + final protected function normalizeQuotedBody($text) { $text = phutil_split_lines($text, true); foreach ($text as $key => $line) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -46,7 +46,7 @@ $is_anchor = false; if (strncmp($link, '/', 1) == 0) { - $base = $engine->getConfig('uri.base'); + $base = phutil_string_cast($engine->getConfig('uri.base')); $base = rtrim($base, '/'); $link = $base.$link; } else if (strncmp($link, '#', 1) == 0) { @@ -134,7 +134,7 @@ public function markupDocumentLink(array $matches) { $uri = trim($matches[1]); - $name = trim(idx($matches, 2)); + $name = trim(idx($matches, 2, '')); if (!$this->isFlatText($uri)) { return $matches[0]; diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupEvalRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupEvalRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupEvalRule.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupEvalRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,100 @@ +<?php + +final class PhutilRemarkupEvalRule extends PhutilRemarkupRule { + + const KEY_EVAL = 'eval'; + + public function getPriority() { + return 50; + } + + public function apply($text) { + return preg_replace_callback( + '/\${{{(.+?)}}}/', + array($this, 'newExpressionToken'), + $text); + } + + public function newExpressionToken(array $matches) { + $expression = $matches[1]; + + if (!$this->isFlatText($expression)) { + return $matches[0]; + } + + $engine = $this->getEngine(); + $token = $engine->storeText($expression); + + $list_key = self::KEY_EVAL; + $expression_list = $engine->getTextMetadata($list_key, array()); + + $expression_list[] = array( + 'token' => $token, + 'expression' => $expression, + 'original' => $matches[0], + ); + + $engine->setTextMetadata($list_key, $expression_list); + + return $token; + } + + public function didMarkupText() { + $engine = $this->getEngine(); + + $list_key = self::KEY_EVAL; + $expression_list = $engine->getTextMetadata($list_key, array()); + + foreach ($expression_list as $expression_item) { + $token = $expression_item['token']; + $expression = $expression_item['expression']; + + $result = $this->evaluateExpression($expression); + + if ($result === null) { + $result = $expression_item['original']; + } + + $engine->overwriteStoredText($token, $result); + } + } + + private function evaluateExpression($expression) { + static $string_map; + + if ($string_map === null) { + $string_map = array( + 'strings' => array( + 'platform' => array( + 'server' => array( + 'name' => PlatformSymbols::getPlatformServerName(), + 'path' => pht('phabricator/'), + ), + 'client' => array( + 'name' => PlatformSymbols::getPlatformClientName(), + 'path' => pht('arcanist/'), + ), + ), + ), + ); + } + + $parts = explode('.', $expression); + + $cursor = $string_map; + foreach ($parts as $part) { + if (isset($cursor[$part])) { + $cursor = $cursor[$part]; + } else { + break; + } + } + + if (is_string($cursor)) { + return $cursor; + } + + return null; + } + +} diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,18 +9,50 @@ } public function apply($text) { + static $angle_pattern; + static $curly_pattern; + static $bare_pattern; + + if ($angle_pattern === null) { + // See T13608. A previous version of this code matched bare URIs + // starting with "\w{3,}", which can take a very long time to match + // against long inputs. + // + // Use a protocol length limit in all patterns for general sanity, + // and a negative lookbehind in the bare pattern to avoid explosive + // complexity during expression evaluation. + + $protocol_fragment = '\w{3,32}'; + $uri_fragment = '[^\s'.PhutilRemarkupBlockStorage::MAGIC_BYTE.']+'; + + $angle_pattern = sprintf( + '(<(%s://%s?)>)', + $protocol_fragment, + $uri_fragment); + + $curly_pattern = sprintf( + '({(%s://%s?)})', + $protocol_fragment, + $uri_fragment); + + $bare_pattern = sprintf( + '((?<!\w)%s://%s)', + $protocol_fragment, + $uri_fragment); + } + // Hyperlinks with explicit "<>" around them get linked exactly, without // the "<>". Angle brackets are basically special and mean "this is a URL // with weird characters". This is assumed to be reasonable because they - // don't appear in normal text or normal URLs. + // don't appear in most normal text or most normal URLs. $text = preg_replace_callback( - '@<(\w{3,}://[^\s'.PhutilRemarkupBlockStorage::MAGIC_BYTE.']+?)>@', + $angle_pattern, array($this, 'markupHyperlinkAngle'), $text); // We match "{uri}", but do not link it by default. $text = preg_replace_callback( - '@{(\w{3,}://[^\s'.PhutilRemarkupBlockStorage::MAGIC_BYTE.']+?)}@', + $curly_pattern, array($this, 'markupHyperlinkCurly'), $text); @@ -31,8 +63,9 @@ // NOTE: We're explicitly avoiding capturing stored blocks, so text like // `http://www.example.com/[[x | y]]` doesn't get aggressively captured. + $text = preg_replace_callback( - '@(\w{3,}://[^\s'.PhutilRemarkupBlockStorage::MAGIC_BYTE.']+)@', + $bare_pattern, array($this, 'markupHyperlinkUngreedy'), $text); @@ -110,7 +143,7 @@ } protected function markupHyperlinkUngreedy($matches) { - $match = $matches[1]; + $match = $matches[0]; $tail = null; $trailing = null; if (preg_match('/[;,.:!?]+$/', $match, $trailing)) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/PhabricatorMarkupEngine.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/PhabricatorMarkupEngine.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/PhabricatorMarkupEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/PhabricatorMarkupEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,10 +42,12 @@ private $objects = array(); private $viewer; private $contextObject; - private $version = 20; + private $version = 21; private $engineCaches = array(); private $auxiliaryConfig = array(); + private static $engineStack = array(); + /* -( Markup Pipeline )---------------------------------------------------- */ @@ -103,6 +105,24 @@ * @task markup */ public function process() { + self::$engineStack[] = $this; + + try { + $result = $this->execute(); + } finally { + array_pop(self::$engineStack); + } + + return $result; + } + + public static function isRenderingEmbeddedContent() { + // See T13678. This prevents cycles when rendering embedded content that + // itself has remarkup fields. + return (count(self::$engineStack) > 1); + } + + private function execute() { $keys = array(); foreach ($this->objects as $key => $info) { if (!isset($info['markup'])) { @@ -504,6 +524,7 @@ $rules = array(); $rules[] = new PhutilRemarkupEscapeRemarkupRule(); + $rules[] = new PhutilRemarkupEvalRule(); $rules[] = new PhutilRemarkupMonospaceRule(); @@ -582,6 +603,14 @@ $engine->setConfig('viewer', $viewer); foreach ($content_blocks as $content_block) { + if ($content_block === null) { + continue; + } + + if (!strlen($content_block)) { + continue; + } + $engine->markupText($content_block); $phids = $engine->getTextMetadata( PhabricatorMentionRemarkupRule::KEY_MENTIONED, @@ -603,7 +632,7 @@ foreach ($content_blocks as $content_block) { $engine->markupText($content_block); $phids = $engine->getTextMetadata( - PhabricatorEmbedFileRemarkupRule::KEY_EMBED_FILE_PHIDS, + PhabricatorEmbedFileRemarkupRule::KEY_ATTACH_INTENT_FILE_PHIDS, array()); foreach ($phids as $phid) { $files[$phid] = $phid; diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php 2022-06-14 16:29:55.000000000 +0000 @@ -42,6 +42,14 @@ return $this->mode & self::MODE_HTML_MAIL; } + public function getQuoteDepth() { + return $this->getConfig('runtime.quote.depth', 0); + } + + public function setQuoteDepth($depth) { + return $this->setConfig('runtime.quote.depth', $depth); + } + public function setBlockRules(array $rules) { assert_instances_of($rules, 'PhutilRemarkupBlockRule'); @@ -255,18 +263,24 @@ } private function markupBlock(array $block) { + $rule = $block['rule']; + + $rule->willMarkupChildBlocks(); + $children = array(); foreach ($block['children'] as $child) { $children[] = $this->markupBlock($child); } + $rule->didMarkupChildBlocks(); + if ($children) { $children = $this->flattenOutput($children); } else { $children = null; } - return $block['rule']->markupText($block['text'], $children); + return $rule->markupText($block['text'], $children); } private function flattenOutput(array $output) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/render.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/render.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/render.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/render.php 2022-06-14 16:29:55.000000000 +0000 @@ -105,6 +105,10 @@ } function phutil_escape_html($string) { + if ($string === null) { + return ''; + } + if ($string instanceof PhutilSafeHTML) { return $string; } else if ($string instanceof PhutilSafeHTMLProducerInterface) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -62,6 +62,22 @@ ), ), array( + 'name' => pht('Enter'), + 'symbol' => "\xE2\x8F\x8E", + 'aliases' => array( + 'enter', + 'return', + ), + ), + array( + 'name' => pht('Control'), + 'symbol' => "\xE2\x8C\x83", + 'aliases' => array( + 'ctrl', + 'control', + ), + ), + array( 'name' => pht('Up'), 'symbol' => "\xE2\x86\x91", 'heavy' => "\xE2\xAC\x86", diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php phabricator-0~git20220903/phabricator/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php --- phabricator-0~git20200925/phabricator/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php 2022-06-14 16:29:55.000000000 +0000 @@ -126,6 +126,12 @@ return $this->renderObjectTagForMail($name, $href, $handle); } + // See T13678. If we're already rendering embedded content, render a + // default reference instead to avoid cycles. + if (PhabricatorMarkupEngine::isRenderingEmbeddedContent()) { + return $this->renderDefaultObjectEmbed($object, $handle); + } + return $this->renderObjectEmbed($object, $handle, $options); } @@ -133,6 +139,12 @@ $object, PhabricatorObjectHandle $handle, $options) { + return $this->renderDefaultObjectEmbed($object, $handle); + } + + final protected function renderDefaultObjectEmbed( + $object, + PhabricatorObjectHandle $handle) { $name = $handle->getFullName(); $href = $handle->getURI(); @@ -306,6 +318,7 @@ 'id' => $matches[1], 'options' => idx($matches, 2), 'original' => $matches[0], + 'quote.depth' => $engine->getQuoteDepth(), )); } @@ -325,6 +338,7 @@ 'id' => $matches[1], 'anchor' => idx($matches, 2), 'original' => $matches[0], + 'quote.depth' => $engine->getQuoteDepth(), )); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/query/PhabricatorQuery.php phabricator-0~git20220903/phabricator/src/infrastructure/query/PhabricatorQuery.php --- phabricator-0~git20200925/phabricator/src/infrastructure/query/PhabricatorQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/query/PhabricatorQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -87,7 +87,7 @@ foreach ($this->flattenSubclause($part) as $subpart) { $result[] = $subpart; } - } else if (strlen($part)) { + } else if (($part !== null) && strlen($part)) { $result[] = $part; } } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php phabricator-0~git20220903/phabricator/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php --- phabricator-0~git20200925/phabricator/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -135,7 +135,7 @@ ); } - final private function getExternalCursorStringForResult($object) { + private function getExternalCursorStringForResult($object) { $cursor = $this->newExternalCursorStringForResult($object); if (!is_string($cursor)) { @@ -154,7 +154,7 @@ return $this->externalCursorString; } - final private function setExternalCursorString($external_cursor) { + private function setExternalCursorString($external_cursor) { $this->externalCursorString = $external_cursor; return $this; } @@ -168,17 +168,17 @@ return $this; } - final private function getInternalCursorObject() { + private function getInternalCursorObject() { return $this->internalCursorObject; } - final private function setInternalCursorObject( + private function setInternalCursorObject( PhabricatorQueryCursor $cursor) { $this->internalCursorObject = $cursor; return $this; } - final private function getInternalCursorFromExternalCursor( + private function getInternalCursorFromExternalCursor( $cursor_string) { $cursor_object = $this->newInternalCursorFromExternalCursor($cursor_string); @@ -196,7 +196,7 @@ return $cursor_object; } - final private function getPagingMapFromCursorObject( + private function getPagingMapFromCursorObject( PhabricatorQueryCursor $cursor, array $keys) { @@ -265,6 +265,24 @@ return $this->ferretMetadata; } + protected function loadPage() { + $object = $this->newResultObject(); + + if (!$object instanceof PhabricatorLiskDAO) { + throw new Exception( + pht( + 'Query class ("%s") did not return the correct type of object '. + 'from "newResultObject()" (expected a subclass of '. + '"PhabricatorLiskDAO", found "%s"). Return an object of the '. + 'expected type (this is common), or implement a custom '. + '"loadPage()" method (this is unusual in modern code).', + get_class($this), + phutil_describe_type($object))); + } + + return $this->loadStandardPage($object); + } + protected function loadStandardPage(PhabricatorLiskDAO $table) { $rows = $this->loadStandardPageRows($table); return $table->loadAllFromArray($rows); @@ -369,10 +387,13 @@ $this->setLimit($limit + 1); - if (strlen($pager->getAfterID())) { - $this->setExternalCursorString($pager->getAfterID()); - } else if ($pager->getBeforeID()) { - $this->setExternalCursorString($pager->getBeforeID()); + $after_id = phutil_string_cast($pager->getAfterID()); + $before_id = phutil_string_cast($pager->getBeforeID()); + + if (phutil_nonempty_string($after_id)) { + $this->setExternalCursorString($after_id); + } else if (phutil_nonempty_string($before_id)) { + $this->setExternalCursorString($before_id); $this->setIsQueryOrderReversed(true); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php phabricator-0~git20220903/phabricator/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php --- phabricator-0~git20200925/phabricator/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php 2022-06-14 16:29:55.000000000 +0000 @@ -234,7 +234,7 @@ // T11773 for some discussion. $this->isOverheated = false; - // See T13386. If we on an old offset-based paging workflow, we need + // See T13386. If we are on an old offset-based paging workflow, we need // to base the overheating limit on both the offset and limit. $overheat_limit = $need * 10; $total_seen = 0; diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php 2022-06-14 16:29:55.000000000 +0000 @@ -77,6 +77,7 @@ } public function escapeStringForLikeClause($value) { + $value = phutil_string_cast($value); $value = addcslashes($value, '\%_'); $value = $this->escapeUTF8String($value); return $value; @@ -347,7 +348,16 @@ case 1142: // Access denied to table case 1143: // Access denied to column case 1227: // Access denied (e.g., no SUPER for SHOW SLAVE STATUS). - throw new AphrontAccessDeniedQueryException($message); + + // See T13622. Try to help users figure out that this is a GRANT + // problem. + + $more = pht( + 'This error usually indicates that you need to "GRANT" the '. + 'MySQL user additional permissions. See "GRANT" in the MySQL '. + 'manual for help.'); + + throw new AphrontAccessDeniedQueryException("{$message}\n\n{$more}"); case 1045: // Access denied (auth) throw new AphrontInvalidCredentialsQueryException($message); case 1146: // No such table diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php 2022-06-14 16:29:55.000000000 +0000 @@ -57,6 +57,13 @@ } } + // See T13588. In PHP 8.1, the default "report mode" for MySQLi has + // changed, which causes MySQLi to raise exceptions. Disable exceptions + // to align behavior with older default behavior under MySQLi, which + // this code expects. Plausibly, this code could be updated to use + // MySQLi exceptions to handle errors under a wider range of PHP versions. + mysqli_report(MYSQLI_REPORT_OFF); + $conn = mysqli_init(); $timeout = $this->getConfiguration('timeout'); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/lisk/LiskDAO.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/lisk/LiskDAO.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/lisk/LiskDAO.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/lisk/LiskDAO.php 2022-06-14 16:29:55.000000000 +0000 @@ -116,7 +116,7 @@ * $pugs = $dog->loadAllWhere('breed = %s', 'Pug'); * $sawyer = $dog->loadOneWhere('name = %s', 'Sawyer'); * - * These methods work like @{function@libphutil:queryfx}, but only take half of + * These methods work like @{function@arcanist:queryfx}, but only take half of * a query (the part after the WHERE keyword). Lisk will handle the connection, * columns, and object construction; you are responsible for the rest of it. * @{method:loadAllWhere} returns a list of objects, while @@ -193,6 +193,8 @@ private static $connections = array(); + private static $liskMetadata = array(); + protected $id; protected $phid; protected $dateCreated; @@ -403,10 +405,11 @@ * @task config */ public function getConfigOption($option_name) { - static $options = null; + $options = $this->getLiskMetadata('config'); - if (!isset($options)) { + if ($options === null) { $options = $this->getConfiguration(); + $this->setLiskMetadata('config', $options); } return idx($options, $option_name); @@ -439,7 +442,7 @@ return $this->loadOneWhere( '%C = %d', - $this->getIDKeyForUse(), + $this->getIDKey(), $id); } @@ -554,7 +557,7 @@ $result = $this->loadOneWhere( '%C = %d', - $this->getIDKeyForUse(), + $this->getIDKey(), $this->getID()); if (!$result) { @@ -579,9 +582,10 @@ * @task load */ public function loadFromArray(array $row) { - static $valid_properties = array(); + $valid_map = $this->getLiskMetadata('validMap', array()); $map = array(); + $updated = false; foreach ($row as $k => $v) { // We permit (but ignore) extra properties in the array because a // common approach to building the array is to issue a raw SELECT query @@ -594,14 +598,15 @@ // path (assigning an invalid property which we've already seen) costs // an empty() plus an isset(). - if (empty($valid_properties[$k])) { - if (isset($valid_properties[$k])) { + if (empty($valid_map[$k])) { + if (isset($valid_map[$k])) { // The value is set but empty, which means it's false, so we've // already determined it's not valid. We don't need to check again. continue; } - $valid_properties[$k] = $this->hasProperty($k); - if (!$valid_properties[$k]) { + $valid_map[$k] = $this->hasProperty($k); + $updated = true; + if (!$valid_map[$k]) { continue; } } @@ -609,6 +614,10 @@ $map[$k] = $v; } + if ($updated) { + $this->setLiskMetadata('validMap', $valid_map); + } + $this->willReadData($map); foreach ($map as $prop => $value) { @@ -686,10 +695,7 @@ * @task save */ public function setID($id) { - static $id_key = null; - if ($id_key === null) { - $id_key = $this->getIDKeyForUse(); - } + $id_key = $this->getIDKey(); $this->$id_key = $id; return $this; } @@ -704,10 +710,7 @@ * @task info */ public function getID() { - static $id_key = null; - if ($id_key === null) { - $id_key = $this->getIDKeyForUse(); - } + $id_key = $this->getIDKey(); return $this->$id_key; } @@ -742,9 +745,10 @@ * @task info */ protected function getAllLiskProperties() { - static $properties = null; - if (!isset($properties)) { - $class = new ReflectionClass(get_class($this)); + $properties = $this->getLiskMetadata('properties'); + + if ($properties === null) { + $class = new ReflectionClass(static::class); $properties = array(); foreach ($class->getProperties(ReflectionProperty::IS_PROTECTED) as $p) { $properties[strtolower($p->getName())] = $p->getName(); @@ -763,7 +767,10 @@ if ($id_key != 'phid' && !$this->getConfigOption(self::CONFIG_AUX_PHID)) { unset($properties['phid']); } + + $this->setLiskMetadata('properties', $properties); } + return $properties; } @@ -777,10 +784,7 @@ * @task info */ protected function checkProperty($property) { - static $properties = null; - if ($properties === null) { - $properties = $this->getAllLiskProperties(); - } + $properties = $this->getAllLiskProperties(); $property = strtolower($property); if (empty($properties[$property])) { @@ -996,7 +1000,7 @@ 'UPDATE %R SET %LQ WHERE %C = '.(is_int($id) ? '%d' : '%s'), $this, $map, - $this->getIDKeyForUse(), + $this->getIDKey(), $id); // We can't detect a missing object because updating an object without // changing any values doesn't affect rows. We could jiggle timestamps @@ -1023,7 +1027,7 @@ $conn->query( 'DELETE FROM %R WHERE %C = %d', $this, - $this->getIDKeyForUse(), + $this->getIDKey(), $this->getID()); $this->didDelete(); @@ -1051,7 +1055,7 @@ // If we are using autoincrement IDs, let MySQL assign the value for the // ID column, if it is empty. If the caller has explicitly provided a // value, use it. - $id_key = $this->getIDKeyForUse(); + $id_key = $this->getIDKey(); if (empty($data[$id_key])) { unset($data[$id_key]); } @@ -1059,7 +1063,7 @@ case self::IDS_COUNTER: // If we are using counter IDs, assign a new ID if we don't already have // one. - $id_key = $this->getIDKeyForUse(); + $id_key = $this->getIDKey(); if (empty($data[$id_key])) { $counter_name = $this->getTableName(); $id = self::loadNextCounterValue($conn, $counter_name); @@ -1175,19 +1179,6 @@ return 'id'; } - - protected function getIDKeyForUse() { - $id_key = $this->getIDKey(); - if (!$id_key) { - throw new Exception( - pht( - 'This DAO does not have a single-part primary key. The method you '. - 'called requires a single-part primary key.')); - } - return $id_key; - } - - /** * Generate a new PHID, used by CONFIG_AUX_PHID. * @@ -1592,22 +1583,12 @@ * @task util */ public function __call($method, $args) { - // NOTE: PHP has a bug that static variables defined in __call() are shared - // across all children classes. Call a different method to work around this - // bug. - return $this->call($method, $args); - } + $dispatch_map = $this->getLiskMetadata('dispatchMap', array()); - /** - * @task util - */ - final protected function call($method, $args) { // NOTE: This method is very performance-sensitive (many thousands of calls // per page on some pages), and thus has some silliness in the name of // optimizations. - static $dispatch_map = array(); - if ($method[0] === 'g') { if (isset($dispatch_map[$method])) { $property = $dispatch_map[$method]; @@ -1620,6 +1601,7 @@ throw new Exception(pht('Bad getter call: %s', $method)); } $dispatch_map[$method] = $property; + $this->setLiskMetadata('dispatchMap', $dispatch_map); } return $this->readField($property); @@ -1632,12 +1614,14 @@ if (substr($method, 0, 3) !== 'set') { throw new Exception(pht("Unable to resolve method '%s'!", $method)); } + $property = substr($method, 3); $property = $this->checkProperty($property); if (!$property) { throw new Exception(pht('Bad setter call: %s', $method)); } $dispatch_map[$method] = $property; + $this->setLiskMetadata('dispatchMap', $dispatch_map); } $this->writeField($property, $args[0]); @@ -1909,4 +1893,20 @@ } + private function getLiskMetadata($key, $default = null) { + if (isset(self::$liskMetadata[static::class][$key])) { + return self::$liskMetadata[static::class][$key]; + } + + if (!isset(self::$liskMetadata[static::class])) { + self::$liskMetadata[static::class] = array(); + } + + return idx(self::$liskMetadata[static::class], $key, $default); + } + + private function setLiskMetadata($key, $value) { + self::$liskMetadata[static::class][$key] = $value; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/lisk/PhabricatorLiskDAO.php 2022-06-14 16:29:55.000000000 +0000 @@ -138,7 +138,7 @@ throw new PhabricatorClusterImproperWriteException( pht( 'Unable to establish a write-mode connection (to application '. - 'database "%s") because Phabricator is in read-only mode. Whatever '. + 'database "%s") because this server is in read-only mode. Whatever '. 'you are trying to do does not function correctly in read-only mode.', $database)); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php 2022-06-14 16:29:55.000000000 +0000 @@ -89,6 +89,17 @@ return $this->namespace.'_'.$fragment; } + public function getInternalDatabaseName($name) { + $namespace = $this->getNamespace(); + + $prefix = $namespace.'_'; + if (strncmp($name, $prefix, strlen($prefix))) { + return null; + } + + return substr($name, strlen($prefix)); + } + public function getDisplayName() { return $this->getRef()->getDisplayName(); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/PhabricatorStoragePatch.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/PhabricatorStoragePatch.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/PhabricatorStoragePatch.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/PhabricatorStoragePatch.php 2022-06-14 16:29:55.000000000 +0000 @@ -9,6 +9,10 @@ private $after; private $legacy; private $dead; + private $phase; + + const PHASE_DEFAULT = 'default'; + const PHASE_WORKER = 'worker'; public function __construct(array $dict) { $this->key = $dict['key']; @@ -18,6 +22,7 @@ $this->name = $dict['name']; $this->after = $dict['after']; $this->dead = $dict['dead']; + $this->phase = $dict['phase']; } public function getLegacy() { @@ -44,6 +49,10 @@ return $this->key; } + public function getPhase() { + return $this->phase; + } + public function isDead() { return $this->dead; } @@ -52,4 +61,31 @@ return ($this->getType() == 'php'); } + public static function getPhaseList() { + return array_keys(self::getPhaseMap()); + } + + public static function getDefaultPhase() { + return self::PHASE_DEFAULT; + } + + private static function getPhaseMap() { + return array( + self::PHASE_DEFAULT => array( + 'order' => 0, + ), + self::PHASE_WORKER => array( + 'order' => 1, + ), + ); + } + + public function newSortVector() { + $map = self::getPhaseMap(); + $phase = $this->getPhase(); + + return id(new PhutilSortVector()) + ->addInt($map[$phase]['order']); + } + } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -7,7 +7,7 @@ $this ->setName('databases') ->setExamples('**databases** [__options__]') - ->setSynopsis(pht('List Phabricator databases.')); + ->setSynopsis(pht('List databases.')); } protected function isReadOnlyWorkflow() { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -47,9 +47,10 @@ } else { $warning = pht( 'Are you completely sure you really want to permanently destroy '. - 'all storage for Phabricator data on host "%s"? This operation '. + 'all storage for %s data on host "%s"? This operation '. 'can not be undone and your data will not be recoverable if '. 'you proceed.', + PlatformSymbols::getPlatformServerName(), $host_display); echo tsprintf( diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,6 +44,16 @@ 'With __--output__, overwrite the output file if it already '. 'exists.'), ), + array( + 'name' => 'database', + 'param' => 'database-name', + 'help' => pht( + 'Dump only tables in the named database (or databases, if '. + 'the flag is repeated). Specify database names without the '. + 'namespace prefix (that is: use "differential", not '. + '"phabricator_differential").'), + 'repeat' => true, + ), )); } @@ -58,6 +68,8 @@ $is_noindex = $args->getArg('no-indexes'); $is_replica = $args->getArg('for-replica'); + $database_filter = $args->getArg('database'); + if ($is_compress) { if ($output_file === null) { throw new PhutilArgumentUsageException( @@ -128,11 +140,60 @@ $schemata = $actual_map[$ref_key]; $expect = $expect_map[$ref_key]; + if ($database_filter) { + $internal_names = array(); + + $expect_databases = $expect->getDatabases(); + foreach ($expect_databases as $expect_database) { + $database_name = $expect_database->getName(); + + $internal_name = $api->getInternalDatabaseName($database_name); + if ($internal_name !== null) { + $internal_names[$internal_name] = $database_name; + } + } + + ksort($internal_names); + + $seen = array(); + foreach ($database_filter as $filter) { + if (!isset($internal_names[$filter])) { + throw new PhutilArgumentUsageException( + pht( + 'Database "%s" is unknown. This script can only dump '. + 'databases known to the current version of this software. '. + 'Valid databases are: %s.', + $filter, + implode(', ', array_keys($internal_names)))); + } + + if (isset($seen[$filter])) { + throw new PhutilArgumentUsageException( + pht( + 'Database "%s" is specified more than once. Specify each '. + 'database at most once.', + $filter)); + } + + $seen[$filter] = true; + } + + $dump_databases = array_select_keys($internal_names, $database_filter); + $dump_databases = array_fuse($dump_databases); + } else { + $dump_databases = array_keys($schemata->getDatabases()); + $dump_databases = array_fuse($dump_databases); + } + $with_caches = $is_replica; $with_indexes = !$is_noindex; $targets = array(); foreach ($schemata->getDatabases() as $database_name => $database) { + if (!isset($dump_databases[$database_name])) { + continue; + } + $expect_database = $expect->getDatabase($database_name); foreach ($database->getTables() as $table_name => $table) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementQuickstartWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementQuickstartWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementQuickstartWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementQuickstartWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -10,7 +10,7 @@ ->setSynopsis( pht( 'Generate a new quickstart database dump. This command is mostly '. - 'useful when developing Phabricator.')) + 'useful for internal development.')) ->setArguments( array( array( diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementStatusWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementStatusWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementStatusWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementStatusWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -33,6 +33,7 @@ $table = id(new PhutilConsoleTable()) ->setShowHeader(false) ->addColumn('id', array('title' => pht('ID'))) + ->addColumn('phase', array('title' => pht('Phase'))) ->addColumn('host', array('title' => pht('Host'))) ->addColumn('status', array('title' => pht('Status'))) ->addColumn('duration', array('title' => pht('Duration'))) @@ -49,16 +50,22 @@ $duration = pht('%s us', new PhutilNumber($duration)); } - $table->addRow(array( - 'id' => $patch->getFullKey(), - 'host' => $ref->getRefKey(), - 'status' => in_array($patch->getFullKey(), $applied) - ? pht('Applied') - : pht('Not Applied'), - 'duration' => $duration, - 'type' => $patch->getType(), - 'name' => $patch->getName(), - )); + if (in_array($patch->getFullKey(), $applied)) { + $status = pht('Applied'); + } else { + $status = pht('Not Applied'); + } + + $table->addRow( + array( + 'id' => $patch->getFullKey(), + 'phase' => $patch->getPhase(), + 'host' => $ref->getRefKey(), + 'status' => $status, + 'duration' => $duration, + 'type' => $patch->getType(), + 'name' => $patch->getName(), + )); } $table->draw(); diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -46,8 +46,8 @@ phutil_console_wrap( pht( 'Before running storage upgrades, you should take down the '. - 'Phabricator web interface and stop any running Phabricator '. - 'daemons (you can disable this warning with %s).', + 'web interface and stop any running daemons (you can disable '. + 'this warning with %s).', '--force'))); if (!phutil_console_confirm(pht('Are you ready to continue?'))) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php 2022-06-14 16:29:55.000000000 +0000 @@ -47,7 +47,7 @@ throw new PhutilArgumentUsageException( pht( - 'Phabricator is configured in cluster mode, with multiple database '. + 'This server is configured in cluster mode, with multiple database '. 'hosts. Use "--host" to specify which host you want to operate on.')); } @@ -98,7 +98,7 @@ } else { throw new PhutilArgumentUsageException( pht( - 'Phabricator is currently in read-only mode. Use --force to '. + 'This server is currently in read-only mode. Use --force to '. 'override this mode.')); } } @@ -156,7 +156,7 @@ return $err; } - final private function doAdjustSchemata( + private function doAdjustSchemata( PhabricatorStorageManagementAPI $api, $unsafe) { @@ -189,7 +189,7 @@ "You can exit this workflow, update MySQL now, and then run this ". "workflow again. This is recommended, but may cause a lot of downtime ". "right now.\n\n". - "You can exit this workflow, continue using Phabricator without ". + "You can exit this workflow, continue using this software without ". "applying adjustments, update MySQL at a later date, and then run ". "this workflow again. This is also a good approach, and will let you ". "delay downtime until later.\n\n". @@ -826,8 +826,8 @@ $message = array(); if ($all_surplus) { $message[] = pht( - 'You have surplus schemata (extra tables or columns which Phabricator '. - 'does not expect). For information on resolving these '. + 'You have surplus schemata (extra tables or columns which this '. + 'software does not expect). For information on resolving these '. 'issues, see the "Surplus Schemata" section in the "Managing Storage '. 'Adjustments" article in the documentation.'); } else if ($all_access) { @@ -844,27 +844,29 @@ $message[] = pht( 'Some of these errors are caused by access control problems. '. 'The user you are connecting with does not have permission to see '. - 'all of the database or tables that Phabricator uses. You need to '. + 'all of the database or tables that this software uses. You need to '. 'GRANT the user more permission, or use a different user.'); } if ($any_surplus) { $message[] = pht( 'Some of these errors are caused by surplus schemata (extra '. - 'tables or columns which Phabricator does not expect). These are '. + 'tables or columns which this software does not expect). These are '. 'not serious. For information on resolving these issues, see the '. '"Surplus Schemata" section in the "Managing Storage Adjustments" '. 'article in the documentation.'); } $message[] = pht( - 'If you are not developing Phabricator itself, report this issue to '. - 'the upstream.'); + 'If you are not developing %s itself, report this issue to '. + 'the upstream.', + PlatformSymbols::getPlatformServerName()); $message[] = pht( - 'If you are developing Phabricator, these errors usually indicate '. + 'If you are developing %s, these errors usually indicate '. 'that your schema specifications do not agree with the schemata your '. - 'code actually builds.'); + 'code actually builds.', + PlatformSymbols::getPlatformServerName()); } $message = implode("\n\n", $message); @@ -913,7 +915,7 @@ } } - final private function doUpgradeSchemata( + private function doUpgradeSchemata( array $apis, $apply_only, $no_quickstart, @@ -922,6 +924,10 @@ $patches = $this->patches; $is_dryrun = $this->dryRun; + // We expect that patches should already be sorted properly. However, + // phase behavior will be wrong if they aren't, so make sure. + $patches = msortv($patches, 'newSortVector'); + $api_map = array(); foreach ($apis as $api) { $api_map[$api->getRef()->getRefKey()] = $api; @@ -1225,7 +1231,7 @@ // log table yet, or may need to adjust it. return PhabricatorGlobalLock::newLock('adjust', $parameters) - ->useSpecificConnection($api->getConn(null)) + ->setExternalConnection($api->getConn(null)) ->setDisableLogging(true) ->lock(); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php 2022-06-14 16:29:55.000000000 +0000 @@ -93,7 +93,6 @@ 'db.conpherence' => array(), 'db.config' => array(), 'db.token' => array(), - 'db.releeph' => array(), 'db.phlux' => array(), 'db.phortune' => array(), 'db.phrequent' => array(), @@ -104,7 +103,6 @@ 'db.policy' => array(), 'db.nuance' => array(), 'db.passphrase' => array(), - 'db.phragment' => array(), 'db.dashboard' => array(), 'db.system' => array(), 'db.fund' => array(), diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php phabricator-0~git20220903/phabricator/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php --- phabricator-0~git20200925/phabricator/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php 2022-06-14 16:29:55.000000000 +0000 @@ -27,10 +27,20 @@ $directory)); } + $patch_type = $matches[1]; + $patch_full_path = rtrim($directory, '/').'/'.$patch; + + $attributes = array(); + if ($patch_type === 'php') { + $attributes = $this->getPHPPatchAttributes( + $patch, + $patch_full_path); + } + $patches[$patch] = array( - 'type' => $matches[1], - 'name' => rtrim($directory, '/').'/'.$patch, - ); + 'type' => $patch_type, + 'name' => $patch_full_path, + ) + $attributes; } return $patches; @@ -45,8 +55,16 @@ $specs = array(); $seen_namespaces = array(); + $phases = PhabricatorStoragePatch::getPhaseList(); + $phases = array_fuse($phases); + + $default_phase = PhabricatorStoragePatch::getDefaultPhase(); + foreach ($patch_lists as $patch_list) { - $last_key = null; + $last_keys = array_fill_keys( + array_keys($phases), + null); + foreach ($patch_list->getPatches() as $key => $patch) { if (!is_array($patch)) { throw new Exception( @@ -63,6 +81,7 @@ 'after' => true, 'legacy' => true, 'dead' => true, + 'phase' => true, ); foreach ($patch as $pkey => $pval) { @@ -128,8 +147,26 @@ $patch['legacy'] = false; } + if (!array_key_exists('phase', $patch)) { + $patch['phase'] = $default_phase; + } + + $patch_phase = $patch['phase']; + + if (!isset($phases[$patch_phase])) { + throw new Exception( + pht( + 'Storage patch "%s" specifies it should apply in phase "%s", '. + 'but this phase is unrecognized. Valid phases are: %s.', + $full_key, + $patch_phase, + implode(', ', array_keys($phases)))); + } + + $last_key = $last_keys[$patch_phase]; + if (!array_key_exists('after', $patch)) { - if ($last_key === null) { + if ($last_key === null && $patch_phase === $default_phase) { throw new Exception( pht( "Patch '%s' is missing key 'after', and is the first patch ". @@ -139,10 +176,14 @@ $full_key, get_class($patch_list))); } else { - $patch['after'] = array($last_key); + if ($last_key === null) { + $patch['after'] = array(); + } else { + $patch['after'] = array($last_key); + } } } - $last_key = $full_key; + $last_keys[$patch_phase] = $full_key; foreach ($patch['after'] as $after_key => $after) { if (strpos($after, ':') === false) { @@ -186,6 +227,21 @@ $key, $after)); } + + $patch_phase = $patch['phase']; + $after_phase = $specs[$after]['phase']; + + if ($patch_phase !== $after_phase) { + throw new Exception( + pht( + 'Storage patch "%s" executes in phase "%s", but depends on '. + 'patch "%s" which is in a different phase ("%s"). Patches '. + 'may not have dependencies across phases.', + $key, + $patch_phase, + $after, + $after_phase)); + } } } @@ -196,7 +252,94 @@ // TODO: Detect cycles? + $patches = msortv($patches, 'newSortVector'); + return $patches; } + private function getPHPPatchAttributes($patch_name, $full_path) { + $data = Filesystem::readFile($full_path); + + $phase_list = PhabricatorStoragePatch::getPhaseList(); + $phase_map = array_fuse($phase_list); + + $attributes = array(); + + $lines = phutil_split_lines($data, false); + foreach ($lines as $line) { + // Skip over the "PHP" line. + if (preg_match('(^<\?)', $line)) { + continue; + } + + // Skip over blank lines. + if (!strlen(trim($line))) { + continue; + } + + // If this is a "//" comment... + if (preg_match('(^\s*//)', $line)) { + $matches = null; + if (preg_match('(^\s*//\s*@(\S+)(?:\s+(.*))?\z)', $line, $matches)) { + $attr_key = $matches[1]; + $attr_value = trim(idx($matches, 2)); + + switch ($attr_key) { + case 'phase': + $phase_name = $attr_value; + + if (!strlen($phase_name)) { + throw new Exception( + pht( + 'Storage patch "%s" specifies a "@phase" attribute with '. + 'no phase value. Phase attributes must specify a value, '. + 'like "@phase default".', + $patch_name)); + } + + if (!isset($phase_map[$phase_name])) { + throw new Exception( + pht( + 'Storage patch "%s" specifies a "@phase" value ("%s"), '. + 'but this is not a recognized phase. Valid phases '. + 'are: %s.', + $patch_name, + $phase_name, + implode(', ', $phase_list))); + } + + if (isset($attributes['phase'])) { + throw new Exception( + pht( + 'Storage patch "%s" specifies a "@phase" value ("%s"), '. + 'but it already has a specified phase ("%s"). Patches '. + 'may not specify multiple phases.', + $patch_name, + $phase_name, + $attributes['phase'])); + } + + $attributes[$attr_key] = $phase_name; + break; + default: + throw new Exception( + pht( + 'Storage patch "%s" specifies attribute "%s", but this '. + 'attribute is unknown.', + $patch_name, + $attr_key)); + } + } + continue; + } + + // If this is anything else, we're all done. Attributes must be marked + // in the header of the file. + break; + } + + + return $attributes; + } + } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/util/password/PhabricatorPasswordHasher.php phabricator-0~git20220903/phabricator/src/infrastructure/util/password/PhabricatorPasswordHasher.php --- phabricator-0~git20200925/phabricator/src/infrastructure/util/password/PhabricatorPasswordHasher.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/util/password/PhabricatorPasswordHasher.php 2022-06-14 16:29:55.000000000 +0000 @@ -307,7 +307,7 @@ throw new PhabricatorPasswordHasherUnavailableException( pht( 'Attempting to compare a password saved with the "%s" hash. No such '. - 'hasher is known to Phabricator.', + 'hasher is known.', $name)); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/util/PhabricatorGlobalLock.php phabricator-0~git20220903/phabricator/src/infrastructure/util/PhabricatorGlobalLock.php --- phabricator-0~git20200925/phabricator/src/infrastructure/util/PhabricatorGlobalLock.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/util/PhabricatorGlobalLock.php 2022-06-14 16:29:55.000000000 +0000 @@ -30,7 +30,7 @@ private $parameters; private $conn; - private $isExternalConnection = false; + private $externalConnection; private $log; private $disableLogging; @@ -91,9 +91,14 @@ * @param AphrontDatabaseConnection * @return this */ - public function useSpecificConnection(AphrontDatabaseConnection $conn) { - $this->conn = $conn; - $this->isExternalConnection = true; + public function setExternalConnection(AphrontDatabaseConnection $conn) { + if ($this->conn) { + throw new Exception( + pht( + 'Lock is already held, and must be released before the '. + 'connection may be changed.')); + } + $this->externalConnection = $conn; return $this; } @@ -103,29 +108,70 @@ } +/* -( Connection Pool )---------------------------------------------------- */ + + public static function getConnectionPoolSize() { + return count(self::$pool); + } + + public static function clearConnectionPool() { + self::$pool = array(); + } + + public static function newConnection() { + // NOTE: Use of the "repository" database is somewhat arbitrary, mostly + // because the first client of locks was the repository daemons. + + // We must always use the same database for all locks, because different + // databases may be on different hosts if the database is partitioned. + + // However, we don't access any tables so we could use any valid database. + // We could build a database-free connection instead, but that's kind of + // messy and unusual. + + $dao = new PhabricatorRepository(); + + // NOTE: Using "force_new" to make sure each lock is on its own connection. + + // See T13627. This is critically important in versions of MySQL older + // than MySQL 5.7, because they can not hold more than one lock per + // connection simultaneously. + + return $dao->establishConnection('w', $force_new = true); + } + /* -( Implementation )----------------------------------------------------- */ protected function doLock($wait) { $conn = $this->conn; if (!$conn) { + if ($this->externalConnection) { + $conn = $this->externalConnection; + } + } + + if (!$conn) { // Try to reuse a connection from the connection pool. $conn = array_pop(self::$pool); } if (!$conn) { - // NOTE: Using the 'repository' database somewhat arbitrarily, mostly - // because the first client of locks is the repository daemons. We must - // always use the same database for all locks, but don't access any - // tables so we could use any valid database. We could build a - // database-free connection instead, but that's kind of messy and we - // might forget about it in the future if we vertically partition the - // application. - $dao = new PhabricatorRepository(); - - // NOTE: Using "force_new" to make sure each lock is on its own - // connection. - $conn = $dao->establishConnection('w', $force_new = true); + $conn = self::newConnection(); + } + + // See T13627. We must never hold more than one lock per connection, so + // make sure this connection has no existing locks. (Normally, we should + // only be able to get here if callers explicitly provide the same external + // connection to multiple locks.) + + if ($conn->isHoldingAnyLock()) { + throw new Exception( + pht( + 'Unable to establish lock on connection: this connection is '. + 'already holding a lock. Acquiring a second lock on the same '. + 'connection would release the first lock in MySQL versions '. + 'older than 5.7.')); } // NOTE: Since MySQL will disconnect us if we're idle for too long, we set @@ -149,12 +195,17 @@ // is still good. We're done with it, so add it to the pool, just as we // would if we were releasing the lock. - // If we don't do this, we may establish a huge number of connections + // If we don't do this, we may establish a huge number of connections // very rapidly if many workers try to acquire a lock at once. For // example, this can happen if there are a large number of webhook tasks // in the queue. - self::$pool[] = $conn; + // See T13627. If this is an external connection, don't put it into + // the shared connection pool. + + if (!$this->externalConnection) { + self::$pool[] = $conn; + } throw id(new PhutilLockException($lock_name)) ->setHint($this->newHint($lock_name, $wait)); @@ -201,9 +252,8 @@ } $this->conn = null; - $this->isExternalConnection = false; - if (!$this->isExternalConnection) { + if (!$this->externalConnection) { $conn->close(); self::$pool[] = $conn; } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/util/PhabricatorHash.php phabricator-0~git20220903/phabricator/src/infrastructure/util/PhabricatorHash.php --- phabricator-0~git20200925/phabricator/src/infrastructure/util/PhabricatorHash.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/util/PhabricatorHash.php 2022-06-14 16:29:55.000000000 +0000 @@ -22,7 +22,7 @@ if (!$key) { throw new Exception( pht( - "Set a '%s' in your Phabricator configuration!", + "Set a '%s' in your configuration!", 'security.hmac-key')); } @@ -224,7 +224,7 @@ $cache_key = "hmac.key({$hmac_name})"; $hmac_key = $cache->getKey($cache_key); - if (!strlen($hmac_key)) { + if (($hmac_key === null) || !strlen($hmac_key)) { $hmac_key = self::readHMACKey($hmac_name); if ($hmac_key === null) { diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/util/PhabricatorMetronome.php phabricator-0~git20220903/phabricator/src/infrastructure/util/PhabricatorMetronome.php --- phabricator-0~git20200925/phabricator/src/infrastructure/util/PhabricatorMetronome.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/util/PhabricatorMetronome.php 2022-06-14 16:29:55.000000000 +0000 @@ -49,7 +49,7 @@ } public function setOffsetFromSeed($seed) { - $offset = PhabricatorHash::digestToRange($seed, 0, PHP_INT_MAX); + $offset = PhabricatorHash::digestToRange($seed, 0, 0x7FFFFFFF); return $this->setOffset($offset); } diff -Nru phabricator-0~git20200925/phabricator/src/infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php phabricator-0~git20220903/phabricator/src/infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php --- phabricator-0~git20200925/phabricator/src/infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,227 @@ +<?php + +final class PhabricatorGlobalLockTestCase + extends PhabricatorTestCase { + + protected function getPhabricatorTestCaseConfiguration() { + return array( + self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true, + ); + } + + public function testConnectionPoolWithDefaultConnection() { + PhabricatorGlobalLock::clearConnectionPool(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Clear Connection Pool')); + + $lock_name = $this->newLockName(); + $lock = PhabricatorGlobalLock::newLock($lock_name); + $lock->lock(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool With Lock')); + + $lock->unlock(); + + $this->assertEqual( + 1, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool With Lock Released')); + + PhabricatorGlobalLock::clearConnectionPool(); + } + + public function testConnectionPoolWithSpecificConnection() { + $conn = PhabricatorGlobalLock::newConnection(); + + PhabricatorGlobalLock::clearConnectionPool(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Clear Connection Pool')); + + $this->assertEqual( + false, + $conn->isHoldingAnyLock(), + pht('Specific Connection, No Lock')); + + $lock_name = $this->newLockName(); + $lock = PhabricatorGlobalLock::newLock($lock_name); + $lock->setExternalConnection($conn); + $lock->lock(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool + Specific, With Lock')); + + $this->assertEqual( + true, + $conn->isHoldingAnyLock(), + pht('Specific Connection, Holding Lock')); + + $lock->unlock(); + + // The specific connection provided should NOT be returned to the + // connection pool. + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool + Specific, With Lock Released')); + + $this->assertEqual( + false, + $conn->isHoldingAnyLock(), + pht('Specific Connection, No Lock')); + + PhabricatorGlobalLock::clearConnectionPool(); + } + + public function testExternalConnectionMutationScope() { + $conn = PhabricatorGlobalLock::newConnection(); + + $lock_name = $this->newLockName(); + $lock = PhabricatorGlobalLock::newLock($lock_name); + $lock->lock(); + + $caught = null; + try { + $lock->setExternalConnection($conn); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + $lock->unlock(); + + $this->assertTrue( + ($caught instanceof Exception), + pht('Changing connection while locked is forbidden.')); + } + + public function testMultipleLocks() { + $conn = PhabricatorGlobalLock::newConnection(); + + PhabricatorGlobalLock::clearConnectionPool(); + + $lock_name_a = $this->newLockName(); + $lock_name_b = $this->newLockName(); + + $lock_a = PhabricatorGlobalLock::newLock($lock_name_a); + $lock_a->setExternalConnection($conn); + + $lock_b = PhabricatorGlobalLock::newLock($lock_name_b); + $lock_b->setExternalConnection($conn); + + $lock_a->lock(); + + $caught = null; + try { + $lock_b->lock(); + } catch (Exception $ex) { + $caught = $ex; + } catch (Throwable $ex) { + $caught = $ex; + } + + // See T13627. The lock infrastructure must forbid this because it does + // not work in versions of MySQL older than 5.7. + + $this->assertTrue( + ($caught instanceof Exception), + pht('Expect multiple locks on the same connection to fail.')); + } + + public function testPoolReleaseOnFailure() { + $conn = PhabricatorGlobalLock::newConnection(); + $lock_name = $this->newLockName(); + + PhabricatorGlobalLock::clearConnectionPool(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Clear Connection Pool')); + + $lock = PhabricatorGlobalLock::newLock($lock_name); + + // NOTE: We're cheating here, since there's a global registry of locks + // for the process that we have to bypass. In the real world, this lock + // would have to be held by some external process. To simplify this + // test case, just use a raw "GET_LOCK()" call to hold the lock. + + $raw_conn = PhabricatorGlobalLock::newConnection(); + $raw_name = $lock->getName(); + + $row = queryfx_one( + $raw_conn, + 'SELECT GET_LOCK(%s, %f)', + $raw_name, + 0); + $this->assertTrue((bool)head($row), pht('Establish Raw Lock')); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool with Held Lock')); + + // We expect this sequence to establish a new connection, fail to acquire + // the lock, then put the connection in the connection pool. After the + // first cycle, the connection should be reused. + + for ($ii = 0; $ii < 3; $ii++) { + $this->tryHeldLock($lock_name); + $this->assertEqual( + 1, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool After Lock Failure')); + } + + PhabricatorGlobalLock::clearConnectionPool(); + + // Now, do the same thing with an external connection. This connection + // should not be put into the pool! See T13627. + + for ($ii = 0; $ii < 3; $ii++) { + $this->tryHeldLock($lock_name, $conn); + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool After External Lock Failure')); + } + } + + private function newLockName() { + return 'testlock-'.Filesystem::readRandomCharacters(16); + } + + private function tryHeldLock( + $lock_name, + AphrontDatabaseConnection $conn = null) { + + $lock = PhabricatorGlobalLock::newLock($lock_name); + + if ($conn) { + $lock->setExternalConnection($conn); + } + + $caught = null; + try { + $lock->lock(0); + } catch (PhutilLockException $ex) { + $caught = $ex; + } + + $this->assertTrue($caught instanceof PhutilLockException); + } + + +} diff -Nru phabricator-0~git20200925/phabricator/src/__phutil_library_map__.php phabricator-0~git20220903/phabricator/src/__phutil_library_map__.php --- phabricator-0~git20200925/phabricator/src/__phutil_library_map__.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/__phutil_library_map__.php 2022-06-14 16:29:55.000000000 +0000 @@ -62,6 +62,8 @@ 'AlmanacDeviceSearchConduitAPIMethod' => 'applications/almanac/conduit/AlmanacDeviceSearchConduitAPIMethod.php', 'AlmanacDeviceSearchEngine' => 'applications/almanac/query/AlmanacDeviceSearchEngine.php', 'AlmanacDeviceSetPropertyTransaction' => 'applications/almanac/xaction/AlmanacDeviceSetPropertyTransaction.php', + 'AlmanacDeviceStatus' => 'applications/almanac/constants/AlmanacDeviceStatus.php', + 'AlmanacDeviceStatusTransaction' => 'applications/almanac/xaction/AlmanacDeviceStatusTransaction.php', 'AlmanacDeviceTransaction' => 'applications/almanac/storage/AlmanacDeviceTransaction.php', 'AlmanacDeviceTransactionQuery' => 'applications/almanac/query/AlmanacDeviceTransactionQuery.php', 'AlmanacDeviceTransactionType' => 'applications/almanac/xaction/AlmanacDeviceTransactionType.php', @@ -86,6 +88,7 @@ 'AlmanacInterfaceSearchEngine' => 'applications/almanac/query/AlmanacInterfaceSearchEngine.php', 'AlmanacInterfaceTableView' => 'applications/almanac/view/AlmanacInterfaceTableView.php', 'AlmanacInterfaceTransaction' => 'applications/almanac/storage/AlmanacInterfaceTransaction.php', + 'AlmanacInterfaceTransactionQuery' => 'applications/almanac/query/AlmanacInterfaceTransactionQuery.php', 'AlmanacInterfaceTransactionType' => 'applications/almanac/xaction/AlmanacInterfaceTransactionType.php', 'AlmanacKeys' => 'applications/almanac/util/AlmanacKeys.php', 'AlmanacManageClusterServicesCapability' => 'applications/almanac/capability/AlmanacManageClusterServicesCapability.php', @@ -236,6 +239,7 @@ 'AphrontIsolatedDatabaseConnection' => 'infrastructure/storage/connection/AphrontIsolatedDatabaseConnection.php', 'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php', 'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php', + 'AphrontJSONHTTPParameterType' => 'aphront/httpparametertype/AphrontJSONHTTPParameterType.php', 'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php', 'AphrontJavelinView' => 'view/AphrontJavelinView.php', 'AphrontKeyboardShortcutsAvailableView' => 'view/widget/AphrontKeyboardShortcutsAvailableView.php', @@ -269,6 +273,7 @@ 'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php', 'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php', 'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php', + 'AphrontRemarkupHTTPParameterType' => 'aphront/httpparametertype/AphrontRemarkupHTTPParameterType.php', 'AphrontRequest' => 'aphront/AphrontRequest.php', 'AphrontRequestExceptionHandler' => 'aphront/handler/AphrontRequestExceptionHandler.php', 'AphrontRequestStream' => 'aphront/requeststream/AphrontRequestStream.php', @@ -336,6 +341,7 @@ 'ChatLogConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogConduitAPIMethod.php', 'ChatLogQueryConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php', 'ChatLogRecordConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php', + 'ConduitAPIDocumentationPage' => 'applications/conduit/data/ConduitAPIDocumentationPage.php', 'ConduitAPIMethod' => 'applications/conduit/method/ConduitAPIMethod.php', 'ConduitAPIMethodTestCase' => 'applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php', 'ConduitAPIRequest' => 'applications/conduit/protocol/ConduitAPIRequest.php', @@ -450,6 +456,7 @@ 'DifferentialActionEmailCommand' => 'applications/differential/command/DifferentialActionEmailCommand.php', 'DifferentialAdjustmentMapTestCase' => 'applications/differential/storage/__tests__/DifferentialAdjustmentMapTestCase.php', 'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php', + 'DifferentialAffectedPathEngine' => 'applications/differential/engine/DifferentialAffectedPathEngine.php', 'DifferentialAsanaRepresentationField' => 'applications/differential/customfield/DifferentialAsanaRepresentationField.php', 'DifferentialAuditorsCommitMessageField' => 'applications/differential/field/DifferentialAuditorsCommitMessageField.php', 'DifferentialAuditorsField' => 'applications/differential/customfield/DifferentialAuditorsField.php', @@ -472,10 +479,12 @@ 'DifferentialChangesetOneUpMailRenderer' => 'applications/differential/render/DifferentialChangesetOneUpMailRenderer.php', 'DifferentialChangesetOneUpRenderer' => 'applications/differential/render/DifferentialChangesetOneUpRenderer.php', 'DifferentialChangesetOneUpTestRenderer' => 'applications/differential/render/DifferentialChangesetOneUpTestRenderer.php', + 'DifferentialChangesetPHIDType' => 'applications/differential/phid/DifferentialChangesetPHIDType.php', 'DifferentialChangesetParser' => 'applications/differential/parser/DifferentialChangesetParser.php', 'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php', 'DifferentialChangesetQuery' => 'applications/differential/query/DifferentialChangesetQuery.php', 'DifferentialChangesetRenderer' => 'applications/differential/render/DifferentialChangesetRenderer.php', + 'DifferentialChangesetSearchConduitAPIMethod' => 'applications/differential/conduit/DifferentialChangesetSearchConduitAPIMethod.php', 'DifferentialChangesetSearchEngine' => 'applications/differential/query/DifferentialChangesetSearchEngine.php', 'DifferentialChangesetTestRenderer' => 'applications/differential/render/DifferentialChangesetTestRenderer.php', 'DifferentialChangesetTwoUpRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpRenderer.php', @@ -491,6 +500,7 @@ 'DifferentialCommitsSearchEngineAttachment' => 'applications/differential/engineextension/DifferentialCommitsSearchEngineAttachment.php', 'DifferentialConduitAPIMethod' => 'applications/differential/conduit/DifferentialConduitAPIMethod.php', 'DifferentialConflictsCommitMessageField' => 'applications/differential/field/DifferentialConflictsCommitMessageField.php', + 'DifferentialConstantsModule' => 'applications/differential/constants/DifferentialConstantsModule.php', 'DifferentialController' => 'applications/differential/controller/DifferentialController.php', 'DifferentialCoreCustomField' => 'applications/differential/customfield/DifferentialCoreCustomField.php', 'DifferentialCreateCommentConduitAPIMethod' => 'applications/differential/conduit/DifferentialCreateCommentConduitAPIMethod.php', @@ -580,7 +590,6 @@ 'DifferentialQueryConduitAPIMethod' => 'applications/differential/conduit/DifferentialQueryConduitAPIMethod.php', 'DifferentialQueryDiffsConduitAPIMethod' => 'applications/differential/conduit/DifferentialQueryDiffsConduitAPIMethod.php', 'DifferentialRawDiffRenderer' => 'applications/differential/render/DifferentialRawDiffRenderer.php', - 'DifferentialReleephRequestFieldSpecification' => 'applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php', 'DifferentialRemarkupRule' => 'applications/differential/remarkup/DifferentialRemarkupRule.php', 'DifferentialReplyHandler' => 'applications/differential/mail/DifferentialReplyHandler.php', 'DifferentialRepositoryField' => 'applications/differential/customfield/DifferentialRepositoryField.php', @@ -611,9 +620,11 @@ 'DifferentialRevisionAcceptTransaction' => 'applications/differential/xaction/DifferentialRevisionAcceptTransaction.php', 'DifferentialRevisionActionTransaction' => 'applications/differential/xaction/DifferentialRevisionActionTransaction.php', 'DifferentialRevisionAffectedFilesHeraldField' => 'applications/differential/herald/DifferentialRevisionAffectedFilesHeraldField.php', + 'DifferentialRevisionAffectedPathsController' => 'applications/differential/controller/DifferentialRevisionAffectedPathsController.php', 'DifferentialRevisionAuthorHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorHeraldField.php', 'DifferentialRevisionAuthorPackagesHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorPackagesHeraldField.php', 'DifferentialRevisionAuthorProjectsHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorProjectsHeraldField.php', + 'DifferentialRevisionAuthorTransaction' => 'applications/differential/xaction/DifferentialRevisionAuthorTransaction.php', 'DifferentialRevisionBuildableTransaction' => 'applications/differential/xaction/DifferentialRevisionBuildableTransaction.php', 'DifferentialRevisionCloseDetailsController' => 'applications/differential/controller/DifferentialRevisionCloseDetailsController.php', 'DifferentialRevisionCloseTransaction' => 'applications/differential/xaction/DifferentialRevisionCloseTransaction.php', @@ -721,6 +732,7 @@ 'DiffusionAuditorsAddAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddAuditorsHeraldAction.php', 'DiffusionAuditorsAddSelfHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddSelfHeraldAction.php', 'DiffusionAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsHeraldAction.php', + 'DiffusionAuditorsSearchEngineAttachment' => 'applications/diffusion/engineextension/DiffusionAuditorsSearchEngineAttachment.php', 'DiffusionBlameConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php', 'DiffusionBlameController' => 'applications/diffusion/controller/DiffusionBlameController.php', 'DiffusionBlameQuery' => 'applications/diffusion/query/blame/DiffusionBlameQuery.php', @@ -895,6 +907,7 @@ 'DiffusionLowLevelResolveRefsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php', 'DiffusionMercurialBlameQuery' => 'applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php', 'DiffusionMercurialCommandEngine' => 'applications/diffusion/protocol/DiffusionMercurialCommandEngine.php', + 'DiffusionMercurialCommandEngineTests' => 'applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php', 'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php', 'DiffusionMercurialFlagInjectionException' => 'applications/diffusion/exception/DiffusionMercurialFlagInjectionException.php', 'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php', @@ -1218,6 +1231,8 @@ 'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php', 'DrydockLeaseUpdateWorker' => 'applications/drydock/worker/DrydockLeaseUpdateWorker.php', 'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php', + 'DrydockLeaseWaitingForActivationLogType' => 'applications/drydock/logtype/DrydockLeaseWaitingForActivationLogType.php', + 'DrydockLeaseWaitingForReclamationLogType' => 'applications/drydock/logtype/DrydockLeaseWaitingForReclamationLogType.php', 'DrydockLeaseWaitingForResourcesLogType' => 'applications/drydock/logtype/DrydockLeaseWaitingForResourcesLogType.php', 'DrydockLog' => 'applications/drydock/storage/DrydockLog.php', 'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php', @@ -1281,7 +1296,6 @@ 'DrydockWorkingCopyBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php', 'EdgeSearchConduitAPIMethod' => 'infrastructure/edges/conduit/EdgeSearchConduitAPIMethod.php', 'FeedConduitAPIMethod' => 'applications/feed/conduit/FeedConduitAPIMethod.php', - 'FeedPublishConduitAPIMethod' => 'applications/feed/conduit/FeedPublishConduitAPIMethod.php', 'FeedPublisherHTTPWorker' => 'applications/feed/worker/FeedPublisherHTTPWorker.php', 'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php', 'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php', @@ -1377,8 +1391,9 @@ 'HarbormasterBuildArtifactPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildArtifactPHIDType.php', 'HarbormasterBuildArtifactQuery' => 'applications/harbormaster/query/HarbormasterBuildArtifactQuery.php', 'HarbormasterBuildAutoplan' => 'applications/harbormaster/autoplan/HarbormasterBuildAutoplan.php', - 'HarbormasterBuildCommand' => 'applications/harbormaster/storage/HarbormasterBuildCommand.php', 'HarbormasterBuildDependencyDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php', + 'HarbormasterBuildEditAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildEditAPIMethod.php', + 'HarbormasterBuildEditEngine' => 'applications/harbormaster/editor/HarbormasterBuildEditEngine.php', 'HarbormasterBuildEngine' => 'applications/harbormaster/engine/HarbormasterBuildEngine.php', 'HarbormasterBuildFailureException' => 'applications/harbormaster/exception/HarbormasterBuildFailureException.php', 'HarbormasterBuildGraph' => 'applications/harbormaster/engine/HarbormasterBuildGraph.php', @@ -1398,7 +1413,12 @@ 'HarbormasterBuildLogView' => 'applications/harbormaster/view/HarbormasterBuildLogView.php', 'HarbormasterBuildLogViewController' => 'applications/harbormaster/controller/HarbormasterBuildLogViewController.php', 'HarbormasterBuildMessage' => 'applications/harbormaster/storage/HarbormasterBuildMessage.php', + 'HarbormasterBuildMessageAbortTransaction' => 'applications/harbormaster/xaction/build/HarbormasterBuildMessageAbortTransaction.php', + 'HarbormasterBuildMessagePauseTransaction' => 'applications/harbormaster/xaction/build/HarbormasterBuildMessagePauseTransaction.php', 'HarbormasterBuildMessageQuery' => 'applications/harbormaster/query/HarbormasterBuildMessageQuery.php', + 'HarbormasterBuildMessageRestartTransaction' => 'applications/harbormaster/xaction/build/HarbormasterBuildMessageRestartTransaction.php', + 'HarbormasterBuildMessageResumeTransaction' => 'applications/harbormaster/xaction/build/HarbormasterBuildMessageResumeTransaction.php', + 'HarbormasterBuildMessageTransaction' => 'applications/harbormaster/xaction/build/HarbormasterBuildMessageTransaction.php', 'HarbormasterBuildPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPHIDType.php', 'HarbormasterBuildPlan' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php', 'HarbormasterBuildPlanBehavior' => 'applications/harbormaster/plan/HarbormasterBuildPlanBehavior.php', @@ -1430,12 +1450,16 @@ 'HarbormasterBuildStep' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStep.php', 'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php', 'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php', + 'HarbormasterBuildStepEditAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildStepEditAPIMethod.php', + 'HarbormasterBuildStepEditEngine' => 'applications/harbormaster/editor/HarbormasterBuildStepEditEngine.php', 'HarbormasterBuildStepEditor' => 'applications/harbormaster/editor/HarbormasterBuildStepEditor.php', 'HarbormasterBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterBuildStepGroup.php', 'HarbormasterBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildStepImplementation.php', 'HarbormasterBuildStepImplementationTestCase' => 'applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php', 'HarbormasterBuildStepPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php', 'HarbormasterBuildStepQuery' => 'applications/harbormaster/query/HarbormasterBuildStepQuery.php', + 'HarbormasterBuildStepSearchAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildStepSearchAPIMethod.php', + 'HarbormasterBuildStepSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildStepSearchEngine.php', 'HarbormasterBuildStepTransaction' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php', 'HarbormasterBuildStepTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildStepTransactionQuery.php', 'HarbormasterBuildTarget' => 'applications/harbormaster/storage/build/HarbormasterBuildTarget.php', @@ -1445,6 +1469,7 @@ 'HarbormasterBuildTransaction' => 'applications/harbormaster/storage/HarbormasterBuildTransaction.php', 'HarbormasterBuildTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php', 'HarbormasterBuildTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildTransactionQuery.php', + 'HarbormasterBuildTransactionType' => 'applications/harbormaster/xaction/build/HarbormasterBuildTransactionType.php', 'HarbormasterBuildUnitMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildUnitMessage.php', 'HarbormasterBuildUnitMessageQuery' => 'applications/harbormaster/query/HarbormasterBuildUnitMessageQuery.php', 'HarbormasterBuildView' => 'applications/harbormaster/view/HarbormasterBuildView.php', @@ -1453,9 +1478,12 @@ 'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php', 'HarbormasterBuildableActionController' => 'applications/harbormaster/controller/HarbormasterBuildableActionController.php', 'HarbormasterBuildableAdapterInterface' => 'applications/harbormaster/herald/HarbormasterBuildableAdapterInterface.php', + 'HarbormasterBuildableEditAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildableEditAPIMethod.php', + 'HarbormasterBuildableEditEngine' => 'applications/harbormaster/editor/HarbormasterBuildableEditEngine.php', 'HarbormasterBuildableEngine' => 'applications/harbormaster/engine/HarbormasterBuildableEngine.php', 'HarbormasterBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildableInterface.php', 'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php', + 'HarbormasterBuildableMessageTransaction' => 'applications/harbormaster/xaction/buildable/HarbormasterBuildableMessageTransaction.php', 'HarbormasterBuildablePHIDType' => 'applications/harbormaster/phid/HarbormasterBuildablePHIDType.php', 'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php', 'HarbormasterBuildableSearchAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildableSearchAPIMethod.php', @@ -1464,6 +1492,7 @@ 'HarbormasterBuildableTransaction' => 'applications/harbormaster/storage/HarbormasterBuildableTransaction.php', 'HarbormasterBuildableTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php', 'HarbormasterBuildableTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildableTransactionQuery.php', + 'HarbormasterBuildableTransactionType' => 'applications/harbormaster/xaction/buildable/HarbormasterBuildableTransactionType.php', 'HarbormasterBuildableViewController' => 'applications/harbormaster/controller/HarbormasterBuildableViewController.php', 'HarbormasterBuildkiteBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildkiteBuildStepImplementation.php', 'HarbormasterBuildkiteBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildkiteBuildableInterface.php', @@ -1498,6 +1527,7 @@ 'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php', 'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php', 'HarbormasterManagementWriteLogWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWriteLogWorkflow.php', + 'HarbormasterMessageException' => 'applications/harbormaster/exception/HarbormasterMessageException.php', 'HarbormasterMessageType' => 'applications/harbormaster/engine/HarbormasterMessageType.php', 'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', 'HarbormasterOtherBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterOtherBuildStepGroup.php', @@ -1509,13 +1539,11 @@ 'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php', 'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php', 'HarbormasterPrototypeBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterPrototypeBuildStepGroup.php', - 'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php', 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryAutotargetsConduitAPIMethod.php', 'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php', 'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php', 'HarbormasterQueryBuildsSearchEngineAttachment' => 'applications/harbormaster/engineextension/HarbormasterQueryBuildsSearchEngineAttachment.php', 'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php', - 'HarbormasterRestartException' => 'applications/harbormaster/exception/HarbormasterRestartException.php', 'HarbormasterRunBuildPlansHeraldAction' => 'applications/harbormaster/herald/HarbormasterRunBuildPlansHeraldAction.php', 'HarbormasterSchemaSpec' => 'applications/harbormaster/storage/HarbormasterSchemaSpec.php', 'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php', @@ -1557,8 +1585,10 @@ 'HeraldBuildableState' => 'applications/herald/state/HeraldBuildableState.php', 'HeraldCallWebhookAction' => 'applications/herald/action/HeraldCallWebhookAction.php', 'HeraldCommentAction' => 'applications/herald/action/HeraldCommentAction.php', + 'HeraldCommentContentField' => 'applications/herald/field/HeraldCommentContentField.php', 'HeraldCommitAdapter' => 'applications/diffusion/herald/HeraldCommitAdapter.php', 'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php', + 'HeraldConditionResult' => 'applications/herald/storage/transcript/HeraldConditionResult.php', 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php', 'HeraldContentSourceField' => 'applications/herald/field/HeraldContentSourceField.php', 'HeraldController' => 'applications/herald/controller/HeraldController.php', @@ -1613,6 +1643,7 @@ 'HeraldRuleDisableTransaction' => 'applications/herald/xaction/HeraldRuleDisableTransaction.php', 'HeraldRuleEditTransaction' => 'applications/herald/xaction/HeraldRuleEditTransaction.php', 'HeraldRuleEditor' => 'applications/herald/editor/HeraldRuleEditor.php', + 'HeraldRuleEvaluationException' => 'applications/herald/engine/exception/HeraldRuleEvaluationException.php', 'HeraldRuleField' => 'applications/herald/field/rule/HeraldRuleField.php', 'HeraldRuleFieldGroup' => 'applications/herald/field/rule/HeraldRuleFieldGroup.php', 'HeraldRuleIndexEngineExtension' => 'applications/herald/engineextension/HeraldRuleIndexEngineExtension.php', @@ -1623,6 +1654,7 @@ 'HeraldRulePHIDType' => 'applications/herald/phid/HeraldRulePHIDType.php', 'HeraldRuleQuery' => 'applications/herald/query/HeraldRuleQuery.php', 'HeraldRuleReplyHandler' => 'applications/herald/mail/HeraldRuleReplyHandler.php', + 'HeraldRuleResult' => 'applications/herald/storage/transcript/HeraldRuleResult.php', 'HeraldRuleSearchEngine' => 'applications/herald/query/HeraldRuleSearchEngine.php', 'HeraldRuleSerializer' => 'applications/herald/editor/HeraldRuleSerializer.php', 'HeraldRuleTestCase' => 'applications/herald/storage/__tests__/HeraldRuleTestCase.php', @@ -1654,6 +1686,7 @@ 'HeraldTranscriptListController' => 'applications/herald/controller/HeraldTranscriptListController.php', 'HeraldTranscriptPHIDType' => 'applications/herald/phid/HeraldTranscriptPHIDType.php', 'HeraldTranscriptQuery' => 'applications/herald/query/HeraldTranscriptQuery.php', + 'HeraldTranscriptResult' => 'applications/herald/storage/transcript/HeraldTranscriptResult.php', 'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php', 'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php', 'HeraldUtilityActionGroup' => 'applications/herald/action/HeraldUtilityActionGroup.php', @@ -1980,7 +2013,6 @@ 'OwnersConduitAPIMethod' => 'applications/owners/conduit/OwnersConduitAPIMethod.php', 'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php', 'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php', - 'OwnersQueryConduitAPIMethod' => 'applications/owners/conduit/OwnersQueryConduitAPIMethod.php', 'OwnersSearchConduitAPIMethod' => 'applications/owners/conduit/OwnersSearchConduitAPIMethod.php', 'PHIDConduitAPIMethod' => 'applications/phid/conduit/PHIDConduitAPIMethod.php', 'PHIDInfoConduitAPIMethod' => 'applications/phid/conduit/PHIDInfoConduitAPIMethod.php', @@ -2008,6 +2040,7 @@ 'PHUICalendarMonthView' => 'view/phui/calendar/PHUICalendarMonthView.php', 'PHUICalendarWeekView' => 'view/phui/calendar/PHUICalendarWeekView.php', 'PHUICalendarWidgetView' => 'view/phui/calendar/PHUICalendarWidgetView.php', + 'PHUIColor' => 'view/phui/PHUIColor.php', 'PHUIColorPalletteExample' => 'applications/uiexample/examples/PHUIColorPalletteExample.php', 'PHUICrumbView' => 'view/phui/PHUICrumbView.php', 'PHUICrumbsView' => 'view/phui/PHUICrumbsView.php', @@ -2292,7 +2325,7 @@ 'PhabricatorAuditManagementDeleteWorkflow' => 'applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php', 'PhabricatorAuditManagementWorkflow' => 'applications/audit/management/PhabricatorAuditManagementWorkflow.php', 'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php', - 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', + 'PhabricatorAuditRequestStatus' => 'applications/audit/constants/PhabricatorAuditRequestStatus.php', 'PhabricatorAuditSynchronizeManagementWorkflow' => 'applications/audit/management/PhabricatorAuditSynchronizeManagementWorkflow.php', 'PhabricatorAuditTransaction' => 'applications/audit/storage/PhabricatorAuditTransaction.php', 'PhabricatorAuditTransactionComment' => 'applications/audit/storage/PhabricatorAuditTransactionComment.php', @@ -3196,6 +3229,7 @@ 'PhabricatorDocumentEngineBlock' => 'applications/files/diff/PhabricatorDocumentEngineBlock.php', 'PhabricatorDocumentEngineBlockDiff' => 'applications/files/diff/PhabricatorDocumentEngineBlockDiff.php', 'PhabricatorDocumentEngineBlocks' => 'applications/files/diff/PhabricatorDocumentEngineBlocks.php', + 'PhabricatorDocumentEngineParserException' => 'applications/files/document/exception/PhabricatorDocumentEngineParserException.php', 'PhabricatorDocumentRef' => 'applications/files/document/PhabricatorDocumentRef.php', 'PhabricatorDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorDocumentRenderingEngine.php', 'PhabricatorDoorkeeperApplication' => 'applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php', @@ -3416,6 +3450,9 @@ 'PhabricatorFerretSearchEngineExtension' => 'applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFileAES256StorageFormat' => 'applications/files/format/PhabricatorFileAES256StorageFormat.php', + 'PhabricatorFileAltTextTransaction' => 'applications/files/xaction/PhabricatorFileAltTextTransaction.php', + 'PhabricatorFileAttachment' => 'applications/files/storage/PhabricatorFileAttachment.php', + 'PhabricatorFileAttachmentQuery' => 'applications/files/query/PhabricatorFileAttachmentQuery.php', 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', 'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php', 'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php', @@ -3426,6 +3463,7 @@ 'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php', 'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php', 'PhabricatorFileDeleteTransaction' => 'applications/files/xaction/PhabricatorFileDeleteTransaction.php', + 'PhabricatorFileDetachController' => 'applications/files/controller/PhabricatorFileDetachController.php', 'PhabricatorFileDocumentController' => 'applications/files/controller/PhabricatorFileDocumentController.php', 'PhabricatorFileDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorFileDocumentRenderingEngine.php', 'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php', @@ -3436,7 +3474,6 @@ 'PhabricatorFileExternalRequest' => 'applications/files/storage/PhabricatorFileExternalRequest.php', 'PhabricatorFileExternalRequestGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileExternalRequestGarbageCollector.php', 'PhabricatorFileFilePHIDType' => 'applications/files/phid/PhabricatorFileFilePHIDType.php', - 'PhabricatorFileHasObjectEdgeType' => 'applications/files/edge/PhabricatorFileHasObjectEdgeType.php', 'PhabricatorFileIconSetSelectController' => 'applications/files/controller/PhabricatorFileIconSetSelectController.php', 'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php', 'PhabricatorFileImageProxyController' => 'applications/files/controller/PhabricatorFileImageProxyController.php', @@ -3471,6 +3508,8 @@ 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php', 'PhabricatorFileTransformTestCase' => 'applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php', + 'PhabricatorFileUICurtainAttachController' => 'applications/files/controller/PhabricatorFileUICurtainAttachController.php', + 'PhabricatorFileUICurtainListController' => 'applications/files/controller/PhabricatorFileUICurtainListController.php', 'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php', 'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php', 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', @@ -3484,6 +3523,7 @@ 'PhabricatorFilesComposeAvatarBuiltinFile' => 'applications/files/builtin/PhabricatorFilesComposeAvatarBuiltinFile.php', 'PhabricatorFilesComposeIconBuiltinFile' => 'applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php', 'PhabricatorFilesConfigOptions' => 'applications/files/config/PhabricatorFilesConfigOptions.php', + 'PhabricatorFilesCurtainExtension' => 'applications/files/engineextension/PhabricatorFilesCurtainExtension.php', 'PhabricatorFilesManagementCatWorkflow' => 'applications/files/management/PhabricatorFilesManagementCatWorkflow.php', 'PhabricatorFilesManagementCompactWorkflow' => 'applications/files/management/PhabricatorFilesManagementCompactWorkflow.php', 'PhabricatorFilesManagementCycleWorkflow' => 'applications/files/management/PhabricatorFilesManagementCycleWorkflow.php', @@ -3537,6 +3577,7 @@ 'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php', 'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php', 'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php', + 'PhabricatorGlobalLockTestCase' => 'infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php', 'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php', 'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php', 'PhabricatorGuidanceContext' => 'applications/guides/guidance/PhabricatorGuidanceContext.php', @@ -3897,7 +3938,6 @@ 'PhabricatorObjectHasAsanaTaskEdgeType' => 'applications/doorkeeper/edge/PhabricatorObjectHasAsanaTaskEdgeType.php', 'PhabricatorObjectHasContributorEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasContributorEdgeType.php', 'PhabricatorObjectHasDraftEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasDraftEdgeType.php', - 'PhabricatorObjectHasFileEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasFileEdgeType.php', 'PhabricatorObjectHasJiraIssueEdgeType' => 'applications/doorkeeper/edge/PhabricatorObjectHasJiraIssueEdgeType.php', 'PhabricatorObjectHasSubscriberEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasSubscriberEdgeType.php', 'PhabricatorObjectHasUnsubscriberEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasUnsubscriberEdgeType.php', @@ -3944,6 +3984,7 @@ 'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php', 'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php', 'PhabricatorOwnersPackageAuditingTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAuditingTransaction.php', + 'PhabricatorOwnersPackageAuthorityTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAuthorityTransaction.php', 'PhabricatorOwnersPackageAutoreviewTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAutoreviewTransaction.php', 'PhabricatorOwnersPackageContextFreeGrammar' => 'applications/owners/lipsum/PhabricatorOwnersPackageContextFreeGrammar.php', 'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php', @@ -4152,6 +4193,7 @@ 'PhabricatorPeopleMailEngine' => 'applications/people/mail/PhabricatorPeopleMailEngine.php', 'PhabricatorPeopleMailEngineException' => 'applications/people/mail/PhabricatorPeopleMailEngineException.php', 'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php', + 'PhabricatorPeopleManagementApproveWorkflow' => 'applications/people/management/PhabricatorPeopleManagementApproveWorkflow.php', 'PhabricatorPeopleManagementEmpowerWorkflow' => 'applications/people/management/PhabricatorPeopleManagementEmpowerWorkflow.php', 'PhabricatorPeopleManagementEnableWorkflow' => 'applications/people/management/PhabricatorPeopleManagementEnableWorkflow.php', 'PhabricatorPeopleManagementWorkflow' => 'applications/people/management/PhabricatorPeopleManagementWorkflow.php', @@ -4197,7 +4239,6 @@ 'PhabricatorPhortuneManagementInvoiceWorkflow' => 'applications/phortune/management/PhabricatorPhortuneManagementInvoiceWorkflow.php', 'PhabricatorPhortuneManagementWorkflow' => 'applications/phortune/management/PhabricatorPhortuneManagementWorkflow.php', 'PhabricatorPhortuneTestCase' => 'applications/phortune/__tests__/PhabricatorPhortuneTestCase.php', - 'PhabricatorPhragmentApplication' => 'applications/phragment/application/PhabricatorPhragmentApplication.php', 'PhabricatorPhrequentApplication' => 'applications/phrequent/application/PhabricatorPhrequentApplication.php', 'PhabricatorPhrictionApplication' => 'applications/phriction/application/PhabricatorPhrictionApplication.php', 'PhabricatorPhurlApplication' => 'applications/phurl/application/PhabricatorPhurlApplication.php', @@ -4236,6 +4277,7 @@ 'PhabricatorPhurlURLViewController' => 'applications/phurl/controller/PhabricatorPhurlURLViewController.php', 'PhabricatorPinnedApplicationsSetting' => 'applications/settings/setting/PhabricatorPinnedApplicationsSetting.php', 'PhabricatorPirateEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorPirateEnglishTranslation.php', + 'PhabricatorPlatform404Controller' => 'applications/base/controller/PhabricatorPlatform404Controller.php', 'PhabricatorPlatformSite' => 'aphront/site/PhabricatorPlatformSite.php', 'PhabricatorPointsEditField' => 'applications/transactions/editfield/PhabricatorPointsEditField.php', 'PhabricatorPointsFact' => 'applications/fact/fact/PhabricatorPointsFact.php', @@ -4265,6 +4307,7 @@ 'PhabricatorPolicyExplainController' => 'applications/policy/controller/PhabricatorPolicyExplainController.php', 'PhabricatorPolicyFavoritesSetting' => 'applications/settings/setting/PhabricatorPolicyFavoritesSetting.php', 'PhabricatorPolicyFilter' => 'applications/policy/filter/PhabricatorPolicyFilter.php', + 'PhabricatorPolicyFilterSet' => 'applications/policy/filter/PhabricatorPolicyFilterSet.php', 'PhabricatorPolicyInterface' => 'applications/policy/interface/PhabricatorPolicyInterface.php', 'PhabricatorPolicyManagementShowWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementShowWorkflow.php', 'PhabricatorPolicyManagementUnlockWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementUnlockWorkflow.php', @@ -4517,8 +4560,6 @@ 'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php', 'PhabricatorRegexListConfigType' => 'applications/config/type/PhabricatorRegexListConfigType.php', 'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php', - 'PhabricatorReleephApplication' => 'applications/releeph/application/PhabricatorReleephApplication.php', - 'PhabricatorReleephApplicationConfigOptions' => 'applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php', 'PhabricatorRemarkupCachePurger' => 'applications/cache/purger/PhabricatorRemarkupCachePurger.php', 'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php', 'PhabricatorRemarkupCowsayBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php', @@ -4588,6 +4629,7 @@ 'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php', 'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php', 'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php', + 'PhabricatorRepositoryManagementLockWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementLockWorkflow.php', 'PhabricatorRepositoryManagementMaintenanceWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMaintenanceWorkflow.php', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php', 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php', @@ -4670,7 +4712,11 @@ 'PhabricatorRequestExceptionHandler' => 'aphront/handler/PhabricatorRequestExceptionHandler.php', 'PhabricatorResetPasswordUserLogType' => 'applications/people/userlog/PhabricatorResetPasswordUserLogType.php', 'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php', - 'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php', + 'PhabricatorRobotsBlogController' => 'applications/system/controller/robots/PhabricatorRobotsBlogController.php', + 'PhabricatorRobotsController' => 'applications/system/controller/robots/PhabricatorRobotsController.php', + 'PhabricatorRobotsPlatformController' => 'applications/system/controller/robots/PhabricatorRobotsPlatformController.php', + 'PhabricatorRobotsResourceController' => 'applications/system/controller/robots/PhabricatorRobotsResourceController.php', + 'PhabricatorRobotsShortController' => 'applications/system/controller/robots/PhabricatorRobotsShortController.php', 'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php', 'PhabricatorSMSAuthFactor' => 'applications/auth/factor/PhabricatorSMSAuthFactor.php', 'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php', @@ -4786,7 +4832,6 @@ 'PhabricatorSlowvoteApplication' => 'applications/slowvote/application/PhabricatorSlowvoteApplication.php', 'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/PhabricatorSlowvoteChoice.php', 'PhabricatorSlowvoteCloseController' => 'applications/slowvote/controller/PhabricatorSlowvoteCloseController.php', - 'PhabricatorSlowvoteCloseTransaction' => 'applications/slowvote/xaction/PhabricatorSlowvoteCloseTransaction.php', 'PhabricatorSlowvoteCommentController' => 'applications/slowvote/controller/PhabricatorSlowvoteCommentController.php', 'PhabricatorSlowvoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteController.php', 'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/PhabricatorSlowvoteDAO.php', @@ -4807,11 +4852,13 @@ 'PhabricatorSlowvoteSchemaSpec' => 'applications/slowvote/storage/PhabricatorSlowvoteSchemaSpec.php', 'PhabricatorSlowvoteSearchEngine' => 'applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php', 'PhabricatorSlowvoteShuffleTransaction' => 'applications/slowvote/xaction/PhabricatorSlowvoteShuffleTransaction.php', + 'PhabricatorSlowvoteStatusTransaction' => 'applications/slowvote/xaction/PhabricatorSlowvoteStatusTransaction.php', 'PhabricatorSlowvoteTransaction' => 'applications/slowvote/storage/PhabricatorSlowvoteTransaction.php', 'PhabricatorSlowvoteTransactionComment' => 'applications/slowvote/storage/PhabricatorSlowvoteTransactionComment.php', 'PhabricatorSlowvoteTransactionQuery' => 'applications/slowvote/query/PhabricatorSlowvoteTransactionQuery.php', 'PhabricatorSlowvoteTransactionType' => 'applications/slowvote/xaction/PhabricatorSlowvoteTransactionType.php', 'PhabricatorSlowvoteVoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteVoteController.php', + 'PhabricatorSlowvoteVotingMethodTransaction' => 'applications/slowvote/xaction/PhabricatorSlowvoteVotingMethodTransaction.php', 'PhabricatorSlug' => 'infrastructure/util/PhabricatorSlug.php', 'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php', 'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php', @@ -5140,9 +5187,11 @@ 'PhabricatorWorkerDestructionEngineExtension' => 'infrastructure/daemon/workers/engineextension/PhabricatorWorkerDestructionEngineExtension.php', 'PhabricatorWorkerLeaseQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php', 'PhabricatorWorkerManagementCancelWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php', + 'PhabricatorWorkerManagementDelayWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementDelayWorkflow.php', 'PhabricatorWorkerManagementExecuteWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementExecuteWorkflow.php', 'PhabricatorWorkerManagementFloodWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementFloodWorkflow.php', 'PhabricatorWorkerManagementFreeWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php', + 'PhabricatorWorkerManagementPriorityWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementPriorityWorkflow.php', 'PhabricatorWorkerManagementRetryWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php', 'PhabricatorWorkerManagementWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php', 'PhabricatorWorkerPermanentFailureException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerPermanentFailureException.php', @@ -5230,6 +5279,7 @@ 'PhameDescriptionView' => 'applications/phame/view/PhameDescriptionView.php', 'PhameDraftListView' => 'applications/phame/view/PhameDraftListView.php', 'PhameHomeController' => 'applications/phame/controller/PhameHomeController.php', + 'PhameInheritBlogPolicyRule' => 'applications/phame/policyrule/PhameInheritBlogPolicyRule.php', 'PhameLiveController' => 'applications/phame/controller/PhameLiveController.php', 'PhameNextPostView' => 'applications/phame/view/PhameNextPostView.php', 'PhamePost' => 'applications/phame/storage/PhamePost.php', @@ -5240,6 +5290,7 @@ 'PhamePostEditConduitAPIMethod' => 'applications/phame/conduit/PhamePostEditConduitAPIMethod.php', 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 'PhamePostEditEngine' => 'applications/phame/editor/PhamePostEditEngine.php', + 'PhamePostEditEngineLock' => 'applications/phame/editor/PhamePostEditEngineLock.php', 'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php', 'PhamePostFerretEngine' => 'applications/phame/search/PhamePostFerretEngine.php', 'PhamePostFulltextEngine' => 'applications/phame/search/PhamePostFulltextEngine.php', @@ -5513,38 +5564,6 @@ 'PhortuneSubscriptionTransactionType' => 'applications/phortune/xaction/subscription/PhortuneSubscriptionTransactionType.php', 'PhortuneSubscriptionWorker' => 'applications/phortune/worker/PhortuneSubscriptionWorker.php', 'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php', - 'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php', - 'PhragmentCanCreateCapability' => 'applications/phragment/capability/PhragmentCanCreateCapability.php', - 'PhragmentConduitAPIMethod' => 'applications/phragment/conduit/PhragmentConduitAPIMethod.php', - 'PhragmentController' => 'applications/phragment/controller/PhragmentController.php', - 'PhragmentCreateController' => 'applications/phragment/controller/PhragmentCreateController.php', - 'PhragmentDAO' => 'applications/phragment/storage/PhragmentDAO.php', - 'PhragmentFragment' => 'applications/phragment/storage/PhragmentFragment.php', - 'PhragmentFragmentPHIDType' => 'applications/phragment/phid/PhragmentFragmentPHIDType.php', - 'PhragmentFragmentQuery' => 'applications/phragment/query/PhragmentFragmentQuery.php', - 'PhragmentFragmentVersion' => 'applications/phragment/storage/PhragmentFragmentVersion.php', - 'PhragmentFragmentVersionPHIDType' => 'applications/phragment/phid/PhragmentFragmentVersionPHIDType.php', - 'PhragmentFragmentVersionQuery' => 'applications/phragment/query/PhragmentFragmentVersionQuery.php', - 'PhragmentGetPatchConduitAPIMethod' => 'applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php', - 'PhragmentHistoryController' => 'applications/phragment/controller/PhragmentHistoryController.php', - 'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php', - 'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php', - 'PhragmentPolicyController' => 'applications/phragment/controller/PhragmentPolicyController.php', - 'PhragmentQueryFragmentsConduitAPIMethod' => 'applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php', - 'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php', - 'PhragmentSchemaSpec' => 'applications/phragment/storage/PhragmentSchemaSpec.php', - 'PhragmentSnapshot' => 'applications/phragment/storage/PhragmentSnapshot.php', - 'PhragmentSnapshotChild' => 'applications/phragment/storage/PhragmentSnapshotChild.php', - 'PhragmentSnapshotChildQuery' => 'applications/phragment/query/PhragmentSnapshotChildQuery.php', - 'PhragmentSnapshotCreateController' => 'applications/phragment/controller/PhragmentSnapshotCreateController.php', - 'PhragmentSnapshotDeleteController' => 'applications/phragment/controller/PhragmentSnapshotDeleteController.php', - 'PhragmentSnapshotPHIDType' => 'applications/phragment/phid/PhragmentSnapshotPHIDType.php', - 'PhragmentSnapshotPromoteController' => 'applications/phragment/controller/PhragmentSnapshotPromoteController.php', - 'PhragmentSnapshotQuery' => 'applications/phragment/query/PhragmentSnapshotQuery.php', - 'PhragmentSnapshotViewController' => 'applications/phragment/controller/PhragmentSnapshotViewController.php', - 'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php', - 'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php', - 'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php', 'PhrequentConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentConduitAPIMethod.php', 'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php', 'PhrequentCurtainExtension' => 'applications/phrequent/engineextension/PhrequentCurtainExtension.php', @@ -5724,6 +5743,7 @@ 'PhutilRemarkupEngine' => 'infrastructure/markup/remarkup/PhutilRemarkupEngine.php', 'PhutilRemarkupEngineTestCase' => 'infrastructure/markup/remarkup/__tests__/PhutilRemarkupEngineTestCase.php', 'PhutilRemarkupEscapeRemarkupRule' => 'infrastructure/markup/markuprule/PhutilRemarkupEscapeRemarkupRule.php', + 'PhutilRemarkupEvalRule' => 'infrastructure/markup/markuprule/PhutilRemarkupEvalRule.php', 'PhutilRemarkupHeaderBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php', 'PhutilRemarkupHighlightRule' => 'infrastructure/markup/markuprule/PhutilRemarkupHighlightRule.php', 'PhutilRemarkupHorizontalRuleBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupHorizontalRuleBlockRule.php', @@ -5844,100 +5864,17 @@ 'ProjectSearchConduitAPIMethod' => 'applications/project/conduit/ProjectSearchConduitAPIMethod.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', 'QueryFuture' => 'infrastructure/storage/future/QueryFuture.php', - 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', - 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', - 'ReleephBranchAccessController' => 'applications/releeph/controller/branch/ReleephBranchAccessController.php', - 'ReleephBranchCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php', - 'ReleephBranchController' => 'applications/releeph/controller/branch/ReleephBranchController.php', - 'ReleephBranchCreateController' => 'applications/releeph/controller/branch/ReleephBranchCreateController.php', - 'ReleephBranchEditController' => 'applications/releeph/controller/branch/ReleephBranchEditController.php', - 'ReleephBranchEditor' => 'applications/releeph/editor/ReleephBranchEditor.php', - 'ReleephBranchHistoryController' => 'applications/releeph/controller/branch/ReleephBranchHistoryController.php', - 'ReleephBranchNamePreviewController' => 'applications/releeph/controller/branch/ReleephBranchNamePreviewController.php', - 'ReleephBranchPHIDType' => 'applications/releeph/phid/ReleephBranchPHIDType.php', - 'ReleephBranchPreviewView' => 'applications/releeph/view/branch/ReleephBranchPreviewView.php', - 'ReleephBranchQuery' => 'applications/releeph/query/ReleephBranchQuery.php', - 'ReleephBranchSearchEngine' => 'applications/releeph/query/ReleephBranchSearchEngine.php', - 'ReleephBranchTemplate' => 'applications/releeph/view/branch/ReleephBranchTemplate.php', - 'ReleephBranchTransaction' => 'applications/releeph/storage/ReleephBranchTransaction.php', - 'ReleephBranchTransactionQuery' => 'applications/releeph/query/ReleephBranchTransactionQuery.php', - 'ReleephBranchViewController' => 'applications/releeph/controller/branch/ReleephBranchViewController.php', - 'ReleephCommitFinder' => 'applications/releeph/commitfinder/ReleephCommitFinder.php', - 'ReleephCommitFinderException' => 'applications/releeph/commitfinder/ReleephCommitFinderException.php', - 'ReleephCommitMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php', - 'ReleephConduitAPIMethod' => 'applications/releeph/conduit/ReleephConduitAPIMethod.php', - 'ReleephController' => 'applications/releeph/controller/ReleephController.php', - 'ReleephDAO' => 'applications/releeph/storage/ReleephDAO.php', - 'ReleephDefaultFieldSelector' => 'applications/releeph/field/selector/ReleephDefaultFieldSelector.php', - 'ReleephDependsOnFieldSpecification' => 'applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php', - 'ReleephDiffChurnFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php', - 'ReleephDiffMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php', - 'ReleephDiffSizeFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php', - 'ReleephFieldParseException' => 'applications/releeph/field/exception/ReleephFieldParseException.php', - 'ReleephFieldSelector' => 'applications/releeph/field/selector/ReleephFieldSelector.php', - 'ReleephFieldSpecification' => 'applications/releeph/field/specification/ReleephFieldSpecification.php', - 'ReleephGetBranchesConduitAPIMethod' => 'applications/releeph/conduit/ReleephGetBranchesConduitAPIMethod.php', - 'ReleephIntentFieldSpecification' => 'applications/releeph/field/specification/ReleephIntentFieldSpecification.php', - 'ReleephLevelFieldSpecification' => 'applications/releeph/field/specification/ReleephLevelFieldSpecification.php', - 'ReleephOriginalCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php', - 'ReleephProductActionController' => 'applications/releeph/controller/product/ReleephProductActionController.php', - 'ReleephProductController' => 'applications/releeph/controller/product/ReleephProductController.php', - 'ReleephProductCreateController' => 'applications/releeph/controller/product/ReleephProductCreateController.php', - 'ReleephProductEditController' => 'applications/releeph/controller/product/ReleephProductEditController.php', - 'ReleephProductEditor' => 'applications/releeph/editor/ReleephProductEditor.php', - 'ReleephProductHistoryController' => 'applications/releeph/controller/product/ReleephProductHistoryController.php', - 'ReleephProductListController' => 'applications/releeph/controller/product/ReleephProductListController.php', - 'ReleephProductPHIDType' => 'applications/releeph/phid/ReleephProductPHIDType.php', - 'ReleephProductQuery' => 'applications/releeph/query/ReleephProductQuery.php', - 'ReleephProductSearchEngine' => 'applications/releeph/query/ReleephProductSearchEngine.php', - 'ReleephProductTransaction' => 'applications/releeph/storage/ReleephProductTransaction.php', - 'ReleephProductTransactionQuery' => 'applications/releeph/query/ReleephProductTransactionQuery.php', - 'ReleephProductViewController' => 'applications/releeph/controller/product/ReleephProductViewController.php', - 'ReleephProject' => 'applications/releeph/storage/ReleephProject.php', - 'ReleephQueryBranchesConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryBranchesConduitAPIMethod.php', - 'ReleephQueryProductsConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryProductsConduitAPIMethod.php', - 'ReleephQueryRequestsConduitAPIMethod' => 'applications/releeph/conduit/ReleephQueryRequestsConduitAPIMethod.php', - 'ReleephReasonFieldSpecification' => 'applications/releeph/field/specification/ReleephReasonFieldSpecification.php', - 'ReleephRequest' => 'applications/releeph/storage/ReleephRequest.php', - 'ReleephRequestActionController' => 'applications/releeph/controller/request/ReleephRequestActionController.php', - 'ReleephRequestCommentController' => 'applications/releeph/controller/request/ReleephRequestCommentController.php', - 'ReleephRequestConduitAPIMethod' => 'applications/releeph/conduit/ReleephRequestConduitAPIMethod.php', - 'ReleephRequestController' => 'applications/releeph/controller/request/ReleephRequestController.php', - 'ReleephRequestDifferentialCreateController' => 'applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php', - 'ReleephRequestEditController' => 'applications/releeph/controller/request/ReleephRequestEditController.php', - 'ReleephRequestMailReceiver' => 'applications/releeph/mail/ReleephRequestMailReceiver.php', - 'ReleephRequestPHIDType' => 'applications/releeph/phid/ReleephRequestPHIDType.php', - 'ReleephRequestQuery' => 'applications/releeph/query/ReleephRequestQuery.php', - 'ReleephRequestReplyHandler' => 'applications/releeph/mail/ReleephRequestReplyHandler.php', - 'ReleephRequestSearchEngine' => 'applications/releeph/query/ReleephRequestSearchEngine.php', - 'ReleephRequestStatus' => 'applications/releeph/constants/ReleephRequestStatus.php', - 'ReleephRequestTransaction' => 'applications/releeph/storage/ReleephRequestTransaction.php', - 'ReleephRequestTransactionComment' => 'applications/releeph/storage/ReleephRequestTransactionComment.php', - 'ReleephRequestTransactionQuery' => 'applications/releeph/query/ReleephRequestTransactionQuery.php', - 'ReleephRequestTransactionalEditor' => 'applications/releeph/editor/ReleephRequestTransactionalEditor.php', - 'ReleephRequestTypeaheadControl' => 'applications/releeph/view/request/ReleephRequestTypeaheadControl.php', - 'ReleephRequestTypeaheadController' => 'applications/releeph/controller/request/ReleephRequestTypeaheadController.php', - 'ReleephRequestView' => 'applications/releeph/view/ReleephRequestView.php', - 'ReleephRequestViewController' => 'applications/releeph/controller/request/ReleephRequestViewController.php', - 'ReleephRequestorFieldSpecification' => 'applications/releeph/field/specification/ReleephRequestorFieldSpecification.php', - 'ReleephRevisionFieldSpecification' => 'applications/releeph/field/specification/ReleephRevisionFieldSpecification.php', - 'ReleephSeverityFieldSpecification' => 'applications/releeph/field/specification/ReleephSeverityFieldSpecification.php', - 'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php', - 'ReleephWorkCanPushConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkCanPushConduitAPIMethod.php', - 'ReleephWorkGetAuthorInfoConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetAuthorInfoConduitAPIMethod.php', - 'ReleephWorkGetBranchCommitMessageConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetBranchCommitMessageConduitAPIMethod.php', - 'ReleephWorkGetBranchConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetBranchConduitAPIMethod.php', - 'ReleephWorkGetCommitMessageConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkGetCommitMessageConduitAPIMethod.php', - 'ReleephWorkNextRequestConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkNextRequestConduitAPIMethod.php', - 'ReleephWorkRecordConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkRecordConduitAPIMethod.php', - 'ReleephWorkRecordPickStatusConduitAPIMethod' => 'applications/releeph/conduit/work/ReleephWorkRecordPickStatusConduitAPIMethod.php', 'RemarkupProcessConduitAPIMethod' => 'applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php', + 'RemarkupValue' => 'applications/remarkup/RemarkupValue.php', 'RepositoryConduitAPIMethod' => 'applications/repository/conduit/RepositoryConduitAPIMethod.php', 'RepositoryQueryConduitAPIMethod' => 'applications/repository/conduit/RepositoryQueryConduitAPIMethod.php', 'ShellLogView' => 'applications/harbormaster/view/ShellLogView.php', 'SlowvoteConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteConduitAPIMethod.php', 'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php', 'SlowvoteInfoConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteInfoConduitAPIMethod.php', + 'SlowvotePollResponseVisibility' => 'applications/slowvote/constants/SlowvotePollResponseVisibility.php', + 'SlowvotePollStatus' => 'applications/slowvote/constants/SlowvotePollStatus.php', + 'SlowvotePollVotingMethod' => 'applications/slowvote/constants/SlowvotePollVotingMethod.php', 'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php', 'SlowvoteSearchConduitAPIMethod' => 'applications/slowvote/conduit/SlowvoteSearchConduitAPIMethod.php', 'SubscriptionListDialogBuilder' => 'applications/subscriptions/view/SubscriptionListDialogBuilder.php', @@ -6062,6 +5999,8 @@ 'AlmanacDeviceSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacDeviceSetPropertyTransaction' => 'AlmanacDeviceTransactionType', + 'AlmanacDeviceStatus' => 'Phobject', + 'AlmanacDeviceStatusTransaction' => 'AlmanacDeviceTransactionType', 'AlmanacDeviceTransaction' => 'AlmanacModularTransaction', 'AlmanacDeviceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacDeviceTransactionType' => 'AlmanacTransactionType', @@ -6093,6 +6032,7 @@ 'AlmanacInterfaceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacInterfaceTableView' => 'AphrontView', 'AlmanacInterfaceTransaction' => 'AlmanacModularTransaction', + 'AlmanacInterfaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacInterfaceTransactionType' => 'AlmanacTransactionType', 'AlmanacKeys' => 'Phobject', 'AlmanacManageClusterServicesCapability' => 'PhabricatorPolicyCapability', @@ -6108,7 +6048,6 @@ 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', - 'AlmanacPropertyInterface', 'PhabricatorDestructibleInterface', 'PhabricatorNgramsInterface', 'PhabricatorConduitResultInterface', @@ -6279,6 +6218,7 @@ 'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink', + 'AphrontJSONHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontJSONResponse' => 'AphrontResponse', 'AphrontJavelinView' => 'AphrontView', 'AphrontKeyboardShortcutsAvailableView' => 'AphrontView', @@ -6315,6 +6255,7 @@ 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontRedirectResponseTestCase' => 'PhabricatorTestCase', 'AphrontReloadResponse' => 'AphrontRedirectResponse', + 'AphrontRemarkupHTTPParameterType' => 'AphrontHTTPParameterType', 'AphrontRequest' => 'Phobject', 'AphrontRequestExceptionHandler' => 'Phobject', 'AphrontRequestStream' => 'Phobject', @@ -6384,6 +6325,7 @@ 'ChatLogConduitAPIMethod' => 'ConduitAPIMethod', 'ChatLogQueryConduitAPIMethod' => 'ChatLogConduitAPIMethod', 'ChatLogRecordConduitAPIMethod' => 'ChatLogConduitAPIMethod', + 'ConduitAPIDocumentationPage' => 'Phobject', 'ConduitAPIMethod' => array( 'Phobject', 'PhabricatorPolicyInterface', @@ -6506,8 +6448,9 @@ 'DarkConsoleXHProfPluginAPI' => 'Phobject', 'DifferentialAction' => 'Phobject', 'DifferentialActionEmailCommand' => 'MetaMTAEmailTransactionCommand', - 'DifferentialAdjustmentMapTestCase' => 'PhutilTestCase', + 'DifferentialAdjustmentMapTestCase' => 'PhabricatorTestCase', 'DifferentialAffectedPath' => 'DifferentialDAO', + 'DifferentialAffectedPathEngine' => 'Phobject', 'DifferentialAsanaRepresentationField' => 'DifferentialCustomField', 'DifferentialAuditorsCommitMessageField' => 'DifferentialCommitMessageCustomField', 'DifferentialAuditorsField' => 'DifferentialStoredCustomField', @@ -6525,6 +6468,7 @@ 'DifferentialDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorConduitResultInterface', ), 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetEngine' => 'Phobject', @@ -6534,10 +6478,12 @@ 'DifferentialChangesetOneUpMailRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetOneUpTestRenderer' => 'DifferentialChangesetTestRenderer', + 'DifferentialChangesetPHIDType' => 'PhabricatorPHIDType', 'DifferentialChangesetParser' => 'Phobject', 'DifferentialChangesetParserTestCase' => 'PhabricatorTestCase', 'DifferentialChangesetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialChangesetRenderer' => 'Phobject', + 'DifferentialChangesetSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'DifferentialChangesetSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DifferentialChangesetTestRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetTwoUpRenderer' => 'DifferentialChangesetHTMLRenderer', @@ -6553,6 +6499,7 @@ 'DifferentialCommitsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'DifferentialConduitAPIMethod' => 'ConduitAPIMethod', 'DifferentialConflictsCommitMessageField' => 'DifferentialCommitMessageField', + 'DifferentialConstantsModule' => 'PhabricatorConfigModule', 'DifferentialController' => 'PhabricatorController', 'DifferentialCoreCustomField' => 'DifferentialCustomField', 'DifferentialCreateCommentConduitAPIMethod' => 'DifferentialConduitAPIMethod', @@ -6656,7 +6603,6 @@ 'DifferentialQueryConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialQueryDiffsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialRawDiffRenderer' => 'Phobject', - 'DifferentialReleephRequestFieldSpecification' => 'Phobject', 'DifferentialRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DifferentialReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'DifferentialRepositoryField' => 'DifferentialCoreCustomField', @@ -6706,9 +6652,11 @@ 'DifferentialRevisionAcceptTransaction' => 'DifferentialRevisionReviewTransaction', 'DifferentialRevisionActionTransaction' => 'DifferentialRevisionTransactionType', 'DifferentialRevisionAffectedFilesHeraldField' => 'DifferentialRevisionHeraldField', + 'DifferentialRevisionAffectedPathsController' => 'DifferentialController', 'DifferentialRevisionAuthorHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionAuthorPackagesHeraldField' => 'DifferentialRevisionHeraldField', 'DifferentialRevisionAuthorProjectsHeraldField' => 'DifferentialRevisionHeraldField', + 'DifferentialRevisionAuthorTransaction' => 'DifferentialRevisionTransactionType', 'DifferentialRevisionBuildableTransaction' => 'DifferentialRevisionTransactionType', 'DifferentialRevisionCloseDetailsController' => 'DifferentialController', 'DifferentialRevisionCloseTransaction' => 'DifferentialRevisionActionTransaction', @@ -6822,6 +6770,7 @@ 'DiffusionAuditorsAddAuditorsHeraldAction' => 'DiffusionAuditorsHeraldAction', 'DiffusionAuditorsAddSelfHeraldAction' => 'DiffusionAuditorsHeraldAction', 'DiffusionAuditorsHeraldAction' => 'HeraldAction', + 'DiffusionAuditorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'DiffusionBlameConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionBlameController' => 'DiffusionController', 'DiffusionBlameQuery' => 'DiffusionQuery', @@ -6999,6 +6948,7 @@ 'DiffusionLowLevelResolveRefsQuery' => 'DiffusionLowLevelQuery', 'DiffusionMercurialBlameQuery' => 'DiffusionBlameQuery', 'DiffusionMercurialCommandEngine' => 'DiffusionCommandEngine', + 'DiffusionMercurialCommandEngineTests' => 'PhabricatorTestCase', 'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionMercurialFlagInjectionException' => 'Exception', 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', @@ -7357,6 +7307,8 @@ 'DrydockLeaseStatus' => 'PhabricatorObjectStatus', 'DrydockLeaseUpdateWorker' => 'DrydockWorker', 'DrydockLeaseViewController' => 'DrydockLeaseController', + 'DrydockLeaseWaitingForActivationLogType' => 'DrydockLogType', + 'DrydockLeaseWaitingForReclamationLogType' => 'DrydockLogType', 'DrydockLeaseWaitingForResourcesLogType' => 'DrydockLogType', 'DrydockLog' => array( 'DrydockDAO', @@ -7430,7 +7382,6 @@ 'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation', 'EdgeSearchConduitAPIMethod' => 'ConduitAPIMethod', 'FeedConduitAPIMethod' => 'ConduitAPIMethod', - 'FeedPublishConduitAPIMethod' => 'FeedConduitAPIMethod', 'FeedPublisherHTTPWorker' => 'FeedPushWorker', 'FeedPublisherWorker' => 'FeedPushWorker', 'FeedPushWorker' => 'PhabricatorWorker', @@ -7553,8 +7504,9 @@ 'HarbormasterBuildArtifactPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildAutoplan' => 'Phobject', - 'HarbormasterBuildCommand' => 'HarbormasterDAO', 'HarbormasterBuildDependencyDatasource' => 'PhabricatorTypeaheadDatasource', + 'HarbormasterBuildEditAPIMethod' => 'PhabricatorEditEngineAPIMethod', + 'HarbormasterBuildEditEngine' => 'PhabricatorEditEngine', 'HarbormasterBuildEngine' => 'Phobject', 'HarbormasterBuildFailureException' => 'Exception', 'HarbormasterBuildGraph' => 'AbstractDirectedGraph', @@ -7583,7 +7535,12 @@ 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), + 'HarbormasterBuildMessageAbortTransaction' => 'HarbormasterBuildMessageTransaction', + 'HarbormasterBuildMessagePauseTransaction' => 'HarbormasterBuildMessageTransaction', 'HarbormasterBuildMessageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'HarbormasterBuildMessageRestartTransaction' => 'HarbormasterBuildMessageTransaction', + 'HarbormasterBuildMessageResumeTransaction' => 'HarbormasterBuildMessageTransaction', + 'HarbormasterBuildMessageTransaction' => 'HarbormasterBuildTransactionType', 'HarbormasterBuildPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildPlan' => array( 'HarbormasterDAO', @@ -7626,18 +7583,23 @@ 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', + 'PhabricatorConduitResultInterface', ), 'HarbormasterBuildStepCoreCustomField' => array( 'HarbormasterBuildStepCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'HarbormasterBuildStepCustomField' => 'PhabricatorCustomField', + 'HarbormasterBuildStepEditAPIMethod' => 'PhabricatorEditEngineAPIMethod', + 'HarbormasterBuildStepEditEngine' => 'PhabricatorEditEngine', 'HarbormasterBuildStepEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildStepGroup' => 'Phobject', 'HarbormasterBuildStepImplementation' => 'Phobject', 'HarbormasterBuildStepImplementationTestCase' => 'PhabricatorTestCase', 'HarbormasterBuildStepPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'HarbormasterBuildStepSearchAPIMethod' => 'PhabricatorSearchEngineAPIMethod', + 'HarbormasterBuildStepSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HarbormasterBuildStepTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildStepTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildTarget' => array( @@ -7649,9 +7611,10 @@ 'HarbormasterBuildTargetPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildTargetSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'HarbormasterBuildTransaction' => 'PhabricatorApplicationTransaction', + 'HarbormasterBuildTransaction' => 'PhabricatorModularTransaction', 'HarbormasterBuildTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'HarbormasterBuildTransactionType' => 'PhabricatorModularTransactionType', 'HarbormasterBuildUnitMessage' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', @@ -7669,16 +7632,20 @@ 'PhabricatorDestructibleInterface', ), 'HarbormasterBuildableActionController' => 'HarbormasterController', + 'HarbormasterBuildableEditAPIMethod' => 'PhabricatorEditEngineAPIMethod', + 'HarbormasterBuildableEditEngine' => 'PhabricatorEditEngine', 'HarbormasterBuildableEngine' => 'Phobject', 'HarbormasterBuildableListController' => 'HarbormasterController', + 'HarbormasterBuildableMessageTransaction' => 'HarbormasterBuildableTransactionType', 'HarbormasterBuildablePHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildableSearchAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'HarbormasterBuildableSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HarbormasterBuildableStatus' => 'Phobject', - 'HarbormasterBuildableTransaction' => 'PhabricatorApplicationTransaction', + 'HarbormasterBuildableTransaction' => 'PhabricatorModularTransaction', 'HarbormasterBuildableTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildableTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'HarbormasterBuildableTransactionType' => 'PhabricatorModularTransactionType', 'HarbormasterBuildableViewController' => 'HarbormasterController', 'HarbormasterBuildkiteBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterBuildkiteHookController' => 'HarbormasterController', @@ -7711,6 +7678,7 @@ 'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementWorkflow' => 'PhabricatorManagementWorkflow', 'HarbormasterManagementWriteLogWorkflow' => 'HarbormasterManagementWorkflow', + 'HarbormasterMessageException' => 'Exception', 'HarbormasterMessageType' => 'Phobject', 'HarbormasterObject' => 'HarbormasterDAO', 'HarbormasterOtherBuildStepGroup' => 'HarbormasterBuildStepGroup', @@ -7722,13 +7690,11 @@ 'HarbormasterPlanRunController' => 'HarbormasterPlanController', 'HarbormasterPlanViewController' => 'HarbormasterPlanController', 'HarbormasterPrototypeBuildStepGroup' => 'HarbormasterBuildStepGroup', - 'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterQueryAutotargetsConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod', 'HarbormasterQueryBuildsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment', 'HarbormasterRemarkupRule' => 'PhabricatorObjectRemarkupRule', - 'HarbormasterRestartException' => 'Exception', 'HarbormasterRunBuildPlansHeraldAction' => 'HeraldAction', 'HarbormasterSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HarbormasterScratchTable' => 'HarbormasterDAO', @@ -7770,11 +7736,13 @@ 'HeraldBuildableState' => 'HeraldState', 'HeraldCallWebhookAction' => 'HeraldAction', 'HeraldCommentAction' => 'HeraldAction', + 'HeraldCommentContentField' => 'HeraldField', 'HeraldCommitAdapter' => array( 'HeraldAdapter', 'HarbormasterBuildableAdapterInterface', ), 'HeraldCondition' => 'HeraldDAO', + 'HeraldConditionResult' => 'HeraldTranscriptResult', 'HeraldConditionTranscript' => 'Phobject', 'HeraldContentSourceField' => 'HeraldField', 'HeraldController' => 'PhabricatorController', @@ -7840,6 +7808,7 @@ 'HeraldRuleDisableTransaction' => 'HeraldRuleTransactionType', 'HeraldRuleEditTransaction' => 'HeraldRuleTransactionType', 'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor', + 'HeraldRuleEvaluationException' => 'Exception', 'HeraldRuleField' => 'HeraldField', 'HeraldRuleFieldGroup' => 'HeraldFieldGroup', 'HeraldRuleIndexEngineExtension' => 'PhabricatorEdgeIndexEngineExtension', @@ -7850,6 +7819,7 @@ 'HeraldRulePHIDType' => 'PhabricatorPHIDType', 'HeraldRuleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HeraldRuleReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', + 'HeraldRuleResult' => 'HeraldTranscriptResult', 'HeraldRuleSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HeraldRuleSerializer' => 'Phobject', 'HeraldRuleTestCase' => 'PhabricatorTestCase', @@ -7885,6 +7855,7 @@ 'HeraldTranscriptListController' => 'HeraldController', 'HeraldTranscriptPHIDType' => 'PhabricatorPHIDType', 'HeraldTranscriptQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'HeraldTranscriptResult' => 'Phobject', 'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HeraldTranscriptTestCase' => 'PhabricatorTestCase', 'HeraldUtilityActionGroup' => 'HeraldActionGroup', @@ -8281,7 +8252,6 @@ 'OwnersConduitAPIMethod' => 'ConduitAPIMethod', 'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler', - 'OwnersQueryConduitAPIMethod' => 'OwnersConduitAPIMethod', 'OwnersSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PHIDConduitAPIMethod' => 'ConduitAPIMethod', 'PHIDInfoConduitAPIMethod' => 'PHIDConduitAPIMethod', @@ -8309,6 +8279,7 @@ 'PHUICalendarMonthView' => 'AphrontView', 'PHUICalendarWeekView' => 'AphrontView', 'PHUICalendarWidgetView' => 'AphrontTagView', + 'PHUIColor' => 'Phobject', 'PHUIColorPalletteExample' => 'PhabricatorUIExample', 'PHUICrumbView' => 'AphrontView', 'PHUICrumbsView' => 'AphrontView', @@ -8618,7 +8589,7 @@ 'PhabricatorAuditManagementDeleteWorkflow' => 'PhabricatorAuditManagementWorkflow', 'PhabricatorAuditManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAuditReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', - 'PhabricatorAuditStatusConstants' => 'Phobject', + 'PhabricatorAuditRequestStatus' => 'Phobject', 'PhabricatorAuditSynchronizeManagementWorkflow' => 'PhabricatorAuditManagementWorkflow', 'PhabricatorAuditTransaction' => 'PhabricatorModularTransaction', 'PhabricatorAuditTransactionComment' => array( @@ -9674,6 +9645,7 @@ 'PhabricatorDocumentEngineBlock' => 'Phobject', 'PhabricatorDocumentEngineBlockDiff' => 'Phobject', 'PhabricatorDocumentEngineBlocks' => 'Phobject', + 'PhabricatorDocumentEngineParserException' => 'Exception', 'PhabricatorDocumentRef' => 'Phobject', 'PhabricatorDocumentRenderingEngine' => 'Phobject', 'PhabricatorDoorkeeperApplication' => 'PhabricatorApplication', @@ -9926,6 +9898,13 @@ 'PhabricatorNgramsInterface', ), 'PhabricatorFileAES256StorageFormat' => 'PhabricatorFileStorageFormat', + 'PhabricatorFileAltTextTransaction' => 'PhabricatorFileTransactionType', + 'PhabricatorFileAttachment' => array( + 'PhabricatorFileDAO', + 'PhabricatorPolicyInterface', + 'PhabricatorExtendedPolicyInterface', + ), + 'PhabricatorFileAttachmentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileBundleLoader' => 'Phobject', 'PhabricatorFileChunk' => array( 'PhabricatorFileDAO', @@ -9943,6 +9922,7 @@ 'PhabricatorFileDataController' => 'PhabricatorFileController', 'PhabricatorFileDeleteController' => 'PhabricatorFileController', 'PhabricatorFileDeleteTransaction' => 'PhabricatorFileTransactionType', + 'PhabricatorFileDetachController' => 'PhabricatorFileController', 'PhabricatorFileDocumentController' => 'PhabricatorFileController', 'PhabricatorFileDocumentRenderingEngine' => 'PhabricatorDocumentRenderingEngine', 'PhabricatorFileDropUploadController' => 'PhabricatorFileController', @@ -9956,7 +9936,6 @@ ), 'PhabricatorFileExternalRequestGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorFileFilePHIDType' => 'PhabricatorPHIDType', - 'PhabricatorFileHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorFileIconSetSelectController' => 'PhabricatorFileController', 'PhabricatorFileImageMacro' => array( 'PhabricatorFileDAO', @@ -9998,6 +9977,8 @@ 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileTransformListController' => 'PhabricatorFileController', 'PhabricatorFileTransformTestCase' => 'PhabricatorTestCase', + 'PhabricatorFileUICurtainAttachController' => 'PhabricatorFileController', + 'PhabricatorFileUICurtainListController' => 'PhabricatorFileController', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileUploadDialogController' => 'PhabricatorFileController', 'PhabricatorFileUploadException' => 'Exception', @@ -10011,6 +9992,7 @@ 'PhabricatorFilesComposeAvatarBuiltinFile' => 'PhabricatorFilesBuiltinFile', 'PhabricatorFilesComposeIconBuiltinFile' => 'PhabricatorFilesBuiltinFile', 'PhabricatorFilesConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorFilesCurtainExtension' => 'PHUICurtainExtension', 'PhabricatorFilesManagementCatWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementCompactWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementCycleWorkflow' => 'PhabricatorFilesManagementWorkflow', @@ -10067,6 +10049,7 @@ 'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGlobalLock' => 'PhutilLock', + 'PhabricatorGlobalLockTestCase' => 'PhabricatorTestCase', 'PhabricatorGlobalUploadTargetView' => 'AphrontView', 'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGuidanceContext' => 'Phobject', @@ -10467,7 +10450,6 @@ 'PhabricatorObjectHasAsanaTaskEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasContributorEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasDraftEdgeType' => 'PhabricatorEdgeType', - 'PhabricatorObjectHasFileEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasJiraIssueEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasSubscriberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasUnsubscriberEdgeType' => 'PhabricatorEdgeType', @@ -10527,6 +10509,7 @@ 'PhabricatorNgramsInterface', ), 'PhabricatorOwnersPackageAuditingTransaction' => 'PhabricatorOwnersPackageTransactionType', + 'PhabricatorOwnersPackageAuthorityTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageAutoreviewTransaction' => 'PhabricatorOwnersPackageTransactionType', 'PhabricatorOwnersPackageContextFreeGrammar' => 'PhutilContextFreeGrammar', 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', @@ -10779,6 +10762,7 @@ 'PhabricatorPeopleMailEngine' => 'Phobject', 'PhabricatorPeopleMailEngineException' => 'Exception', 'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem', + 'PhabricatorPeopleManagementApproveWorkflow' => 'PhabricatorPeopleManagementWorkflow', 'PhabricatorPeopleManagementEmpowerWorkflow' => 'PhabricatorPeopleManagementWorkflow', 'PhabricatorPeopleManagementEnableWorkflow' => 'PhabricatorPeopleManagementWorkflow', 'PhabricatorPeopleManagementWorkflow' => 'PhabricatorManagementWorkflow', @@ -10824,7 +10808,6 @@ 'PhabricatorPhortuneManagementInvoiceWorkflow' => 'PhabricatorPhortuneManagementWorkflow', 'PhabricatorPhortuneManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorPhortuneTestCase' => 'PhabricatorTestCase', - 'PhabricatorPhragmentApplication' => 'PhabricatorApplication', 'PhabricatorPhrequentApplication' => 'PhabricatorApplication', 'PhabricatorPhrictionApplication' => 'PhabricatorApplication', 'PhabricatorPhurlApplication' => 'PhabricatorApplication', @@ -10876,6 +10859,7 @@ 'PhabricatorPhurlURLViewController' => 'PhabricatorPhurlController', 'PhabricatorPinnedApplicationsSetting' => 'PhabricatorInternalSetting', 'PhabricatorPirateEnglishTranslation' => 'PhutilTranslation', + 'PhabricatorPlatform404Controller' => 'PhabricatorController', 'PhabricatorPlatformSite' => 'PhabricatorSite', 'PhabricatorPointsEditField' => 'PhabricatorEditField', 'PhabricatorPointsFact' => 'PhabricatorFact', @@ -10908,6 +10892,7 @@ 'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController', 'PhabricatorPolicyFavoritesSetting' => 'PhabricatorInternalSetting', 'PhabricatorPolicyFilter' => 'Phobject', + 'PhabricatorPolicyFilterSet' => 'Phobject', 'PhabricatorPolicyInterface' => 'PhabricatorPHIDInterface', 'PhabricatorPolicyManagementShowWorkflow' => 'PhabricatorPolicyManagementWorkflow', 'PhabricatorPolicyManagementUnlockWorkflow' => 'PhabricatorPolicyManagementWorkflow', @@ -11209,8 +11194,6 @@ 'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController', 'PhabricatorRegexListConfigType' => 'PhabricatorTextListConfigType', 'PhabricatorRegistrationProfile' => 'Phobject', - 'PhabricatorReleephApplication' => 'PhabricatorApplication', - 'PhabricatorReleephApplicationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRemarkupCachePurger' => 'PhabricatorCachePurger', 'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl', 'PhabricatorRemarkupCowsayBlockInterpreter' => 'PhutilRemarkupBlockInterpreter', @@ -11325,6 +11308,7 @@ 'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow', + 'PhabricatorRepositoryManagementLockWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMaintenanceWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'PhabricatorRepositoryManagementWorkflow', @@ -11431,7 +11415,11 @@ 'PhabricatorRequestExceptionHandler' => 'AphrontRequestExceptionHandler', 'PhabricatorResetPasswordUserLogType' => 'PhabricatorUserLogType', 'PhabricatorResourceSite' => 'PhabricatorSite', + 'PhabricatorRobotsBlogController' => 'PhabricatorRobotsController', 'PhabricatorRobotsController' => 'PhabricatorController', + 'PhabricatorRobotsPlatformController' => 'PhabricatorRobotsController', + 'PhabricatorRobotsResourceController' => 'PhabricatorRobotsController', + 'PhabricatorRobotsShortController' => 'PhabricatorRobotsController', 'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorSMSAuthFactor' => 'PhabricatorAuthFactor', 'PhabricatorSQLPatchList' => 'Phobject', @@ -11549,7 +11537,6 @@ 'PhabricatorSlowvoteApplication' => 'PhabricatorApplication', 'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvoteCloseController' => 'PhabricatorSlowvoteController', - 'PhabricatorSlowvoteCloseTransaction' => 'PhabricatorSlowvoteTransactionType', 'PhabricatorSlowvoteCommentController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteController' => 'PhabricatorController', 'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO', @@ -11581,11 +11568,13 @@ 'PhabricatorSlowvoteSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorSlowvoteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSlowvoteShuffleTransaction' => 'PhabricatorSlowvoteTransactionType', + 'PhabricatorSlowvoteStatusTransaction' => 'PhabricatorSlowvoteTransactionType', 'PhabricatorSlowvoteTransaction' => 'PhabricatorModularTransaction', 'PhabricatorSlowvoteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorSlowvoteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorSlowvoteTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorSlowvoteVoteController' => 'PhabricatorSlowvoteController', + 'PhabricatorSlowvoteVotingMethodTransaction' => 'PhabricatorSlowvoteTransactionType', 'PhabricatorSlug' => 'Phobject', 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 'PhabricatorSourceCodeView' => 'AphrontView', @@ -11962,9 +11951,11 @@ 'PhabricatorWorkerDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorWorkerLeaseQuery' => 'PhabricatorQuery', 'PhabricatorWorkerManagementCancelWorkflow' => 'PhabricatorWorkerManagementWorkflow', + 'PhabricatorWorkerManagementDelayWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementExecuteWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementFloodWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementFreeWorkflow' => 'PhabricatorWorkerManagementWorkflow', + 'PhabricatorWorkerManagementPriorityWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementRetryWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorWorkerPermanentFailureException' => 'Exception', @@ -12071,6 +12062,7 @@ 'PhameDescriptionView' => 'AphrontTagView', 'PhameDraftListView' => 'AphrontTagView', 'PhameHomeController' => 'PhamePostController', + 'PhameInheritBlogPolicyRule' => 'PhabricatorPolicyRule', 'PhameLiveController' => 'PhameController', 'PhameNextPostView' => 'AphrontTagView', 'PhamePost' => array( @@ -12084,6 +12076,7 @@ 'PhabricatorDestructibleInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorConduitResultInterface', + 'PhabricatorEditEngineLockableInterface', 'PhabricatorFulltextInterface', 'PhabricatorFerretInterface', ), @@ -12094,6 +12087,7 @@ 'PhamePostEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhamePostEditController' => 'PhamePostController', 'PhamePostEditEngine' => 'PhabricatorEditEngine', + 'PhamePostEditEngineLock' => 'PhabricatorEditEngineLock', 'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor', 'PhamePostFerretEngine' => 'PhabricatorFerretEngine', 'PhamePostFulltextEngine' => 'PhabricatorFulltextEngine', @@ -12434,50 +12428,6 @@ 'PhortuneSubscriptionTransactionType' => 'PhabricatorModularTransactionType', 'PhortuneSubscriptionWorker' => 'PhabricatorWorker', 'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider', - 'PhragmentBrowseController' => 'PhragmentController', - 'PhragmentCanCreateCapability' => 'PhabricatorPolicyCapability', - 'PhragmentConduitAPIMethod' => 'ConduitAPIMethod', - 'PhragmentController' => 'PhabricatorController', - 'PhragmentCreateController' => 'PhragmentController', - 'PhragmentDAO' => 'PhabricatorLiskDAO', - 'PhragmentFragment' => array( - 'PhragmentDAO', - 'PhabricatorPolicyInterface', - ), - 'PhragmentFragmentPHIDType' => 'PhabricatorPHIDType', - 'PhragmentFragmentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhragmentFragmentVersion' => array( - 'PhragmentDAO', - 'PhabricatorPolicyInterface', - ), - 'PhragmentFragmentVersionPHIDType' => 'PhabricatorPHIDType', - 'PhragmentFragmentVersionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhragmentGetPatchConduitAPIMethod' => 'PhragmentConduitAPIMethod', - 'PhragmentHistoryController' => 'PhragmentController', - 'PhragmentPatchController' => 'PhragmentController', - 'PhragmentPatchUtil' => 'Phobject', - 'PhragmentPolicyController' => 'PhragmentController', - 'PhragmentQueryFragmentsConduitAPIMethod' => 'PhragmentConduitAPIMethod', - 'PhragmentRevertController' => 'PhragmentController', - 'PhragmentSchemaSpec' => 'PhabricatorConfigSchemaSpec', - 'PhragmentSnapshot' => array( - 'PhragmentDAO', - 'PhabricatorPolicyInterface', - ), - 'PhragmentSnapshotChild' => array( - 'PhragmentDAO', - 'PhabricatorPolicyInterface', - ), - 'PhragmentSnapshotChildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhragmentSnapshotCreateController' => 'PhragmentController', - 'PhragmentSnapshotDeleteController' => 'PhragmentController', - 'PhragmentSnapshotPHIDType' => 'PhabricatorPHIDType', - 'PhragmentSnapshotPromoteController' => 'PhragmentController', - 'PhragmentSnapshotQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhragmentSnapshotViewController' => 'PhragmentController', - 'PhragmentUpdateController' => 'PhragmentController', - 'PhragmentVersionController' => 'PhragmentController', - 'PhragmentZIPController' => 'PhragmentController', 'PhrequentConduitAPIMethod' => 'ConduitAPIMethod', 'PhrequentController' => 'PhabricatorController', 'PhrequentCurtainExtension' => 'PHUICurtainExtension', @@ -12677,6 +12627,7 @@ 'PhutilRemarkupEngine' => 'PhutilMarkupEngine', 'PhutilRemarkupEngineTestCase' => 'PhutilTestCase', 'PhutilRemarkupEscapeRemarkupRule' => 'PhutilRemarkupRule', + 'PhutilRemarkupEvalRule' => 'PhutilRemarkupRule', 'PhutilRemarkupHeaderBlockRule' => 'PhutilRemarkupBlockRule', 'PhutilRemarkupHighlightRule' => 'PhutilRemarkupRule', 'PhutilRemarkupHorizontalRuleBlockRule' => 'PhutilRemarkupBlockRule', @@ -12817,116 +12768,17 @@ 'ProjectSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'QueryFormattingTestCase' => 'PhabricatorTestCase', 'QueryFuture' => 'Future', - 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephBranch' => array( - 'ReleephDAO', - 'PhabricatorApplicationTransactionInterface', - 'PhabricatorPolicyInterface', - ), - 'ReleephBranchAccessController' => 'ReleephBranchController', - 'ReleephBranchCommitFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephBranchController' => 'ReleephController', - 'ReleephBranchCreateController' => 'ReleephProductController', - 'ReleephBranchEditController' => 'ReleephBranchController', - 'ReleephBranchEditor' => 'PhabricatorEditor', - 'ReleephBranchHistoryController' => 'ReleephBranchController', - 'ReleephBranchNamePreviewController' => 'ReleephController', - 'ReleephBranchPHIDType' => 'PhabricatorPHIDType', - 'ReleephBranchPreviewView' => 'AphrontFormControl', - 'ReleephBranchQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'ReleephBranchSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'ReleephBranchTemplate' => 'Phobject', - 'ReleephBranchTransaction' => 'PhabricatorApplicationTransaction', - 'ReleephBranchTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'ReleephBranchViewController' => 'ReleephBranchController', - 'ReleephCommitFinder' => 'Phobject', - 'ReleephCommitFinderException' => 'Exception', - 'ReleephCommitMessageFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephConduitAPIMethod' => 'ConduitAPIMethod', - 'ReleephController' => 'PhabricatorController', - 'ReleephDAO' => 'PhabricatorLiskDAO', - 'ReleephDefaultFieldSelector' => 'ReleephFieldSelector', - 'ReleephDependsOnFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephDiffChurnFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephDiffMessageFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephDiffSizeFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephFieldParseException' => 'Exception', - 'ReleephFieldSelector' => 'Phobject', - 'ReleephFieldSpecification' => array( - 'PhabricatorCustomField', - 'PhabricatorMarkupInterface', - ), - 'ReleephGetBranchesConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephIntentFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephLevelFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephOriginalCommitFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephProductActionController' => 'ReleephProductController', - 'ReleephProductController' => 'ReleephController', - 'ReleephProductCreateController' => 'ReleephProductController', - 'ReleephProductEditController' => 'ReleephProductController', - 'ReleephProductEditor' => 'PhabricatorApplicationTransactionEditor', - 'ReleephProductHistoryController' => 'ReleephProductController', - 'ReleephProductListController' => 'ReleephController', - 'ReleephProductPHIDType' => 'PhabricatorPHIDType', - 'ReleephProductQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'ReleephProductSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'ReleephProductTransaction' => 'PhabricatorApplicationTransaction', - 'ReleephProductTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'ReleephProductViewController' => 'ReleephProductController', - 'ReleephProject' => array( - 'ReleephDAO', - 'PhabricatorApplicationTransactionInterface', - 'PhabricatorPolicyInterface', - ), - 'ReleephQueryBranchesConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephQueryProductsConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephQueryRequestsConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephReasonFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephRequest' => array( - 'ReleephDAO', - 'PhabricatorApplicationTransactionInterface', - 'PhabricatorPolicyInterface', - 'PhabricatorCustomFieldInterface', - ), - 'ReleephRequestActionController' => 'ReleephRequestController', - 'ReleephRequestCommentController' => 'ReleephRequestController', - 'ReleephRequestConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephRequestController' => 'ReleephController', - 'ReleephRequestDifferentialCreateController' => 'ReleephController', - 'ReleephRequestEditController' => 'ReleephBranchController', - 'ReleephRequestMailReceiver' => 'PhabricatorObjectMailReceiver', - 'ReleephRequestPHIDType' => 'PhabricatorPHIDType', - 'ReleephRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'ReleephRequestReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', - 'ReleephRequestSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'ReleephRequestStatus' => 'Phobject', - 'ReleephRequestTransaction' => 'PhabricatorApplicationTransaction', - 'ReleephRequestTransactionComment' => 'PhabricatorApplicationTransactionComment', - 'ReleephRequestTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'ReleephRequestTransactionalEditor' => 'PhabricatorApplicationTransactionEditor', - 'ReleephRequestTypeaheadControl' => 'AphrontFormControl', - 'ReleephRequestTypeaheadController' => 'PhabricatorTypeaheadDatasourceController', - 'ReleephRequestView' => 'AphrontView', - 'ReleephRequestViewController' => 'ReleephBranchController', - 'ReleephRequestorFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephRevisionFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephSeverityFieldSpecification' => 'ReleephLevelFieldSpecification', - 'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephWorkCanPushConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephWorkGetAuthorInfoConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephWorkGetBranchCommitMessageConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephWorkGetBranchConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephWorkGetCommitMessageConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephWorkNextRequestConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephWorkRecordConduitAPIMethod' => 'ReleephConduitAPIMethod', - 'ReleephWorkRecordPickStatusConduitAPIMethod' => 'ReleephConduitAPIMethod', 'RemarkupProcessConduitAPIMethod' => 'ConduitAPIMethod', + 'RemarkupValue' => 'Phobject', 'RepositoryConduitAPIMethod' => 'ConduitAPIMethod', 'RepositoryQueryConduitAPIMethod' => 'RepositoryConduitAPIMethod', 'ShellLogView' => 'AphrontView', 'SlowvoteConduitAPIMethod' => 'ConduitAPIMethod', 'SlowvoteEmbedView' => 'AphrontView', 'SlowvoteInfoConduitAPIMethod' => 'SlowvoteConduitAPIMethod', + 'SlowvotePollResponseVisibility' => 'Phobject', + 'SlowvotePollStatus' => 'Phobject', + 'SlowvotePollVotingMethod' => 'Phobject', 'SlowvoteRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'SlowvoteSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'SubscriptionListDialogBuilder' => 'Phobject', diff -Nru phabricator-0~git20200925/phabricator/src/view/form/control/AphrontFormTextAreaControl.php phabricator-0~git20220903/phabricator/src/view/form/control/AphrontFormTextAreaControl.php --- phabricator-0~git20200925/phabricator/src/view/form/control/AphrontFormTextAreaControl.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/form/control/AphrontFormTextAreaControl.php 2022-06-14 16:29:55.000000000 +0000 @@ -73,7 +73,7 @@ // NOTE: This needs to be string cast, because if we pass `null` the // tag will be self-closed and some browsers aren't thrilled about that. - $value = (string)$this->getValue(); + $value = phutil_string_cast($this->getValue()); // NOTE: We also need to prefix the string with a newline, because browsers // ignore a newline immediately after a <textarea> tag, so they'll eat diff -Nru phabricator-0~git20200925/phabricator/src/view/form/control/PhabricatorRemarkupControl.php phabricator-0~git20220903/phabricator/src/view/form/control/PhabricatorRemarkupControl.php --- phabricator-0~git20200925/phabricator/src/view/form/control/PhabricatorRemarkupControl.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/form/control/PhabricatorRemarkupControl.php 2022-06-14 16:29:55.000000000 +0000 @@ -1,16 +1,12 @@ <?php -final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl { +final class PhabricatorRemarkupControl + extends AphrontFormTextAreaControl { - private $disableMacro = false; private $disableFullScreen = false; private $canPin; private $sendOnEnter = false; - - public function setDisableMacros($disable) { - $this->disableMacro = $disable; - return $this; - } + private $remarkupMetadata = array(); public function setDisableFullScreen($disable) { $this->disableFullScreen = $disable; @@ -35,6 +31,24 @@ return $this->sendOnEnter; } + public function setRemarkupMetadata(array $value) { + $this->remarkupMetadata = $value; + return $this; + } + + public function getRemarkupMetadata() { + return $this->remarkupMetadata; + } + + public function setValue($value) { + if ($value instanceof RemarkupValue) { + $this->setRemarkupMetadata($value->getMetadata()); + $value = $value->getCorpus(); + } + + return parent::setValue($value); + } + protected function renderInput() { $id = $this->getID(); if (!$id) { @@ -47,6 +61,25 @@ throw new PhutilInvalidStateException('setUser'); } + // NOTE: Metadata is passed to Javascript in a structured way, and also + // dumped directly into the form as an encoded string. This makes it less + // likely that we'll lose server-provided metadata (for example, from a + // saved draft) if there is a client-side error. + + $metadata_name = $this->getName().'_metadata'; + $metadata_value = (object)$this->getRemarkupMetadata(); + $metadata_string = phutil_json_encode($metadata_value); + + $metadata_id = celerity_generate_unique_node_id(); + $metadata_input = phutil_tag( + 'input', + array( + 'type' => 'hidden', + 'id' => $metadata_id, + 'name' => $metadata_name, + 'value' => $metadata_string, + )); + // We need to have this if previews render images, since Ajax can not // currently ship JS or CSS. require_celerity_resource('phui-lightbox-css'); @@ -56,6 +89,8 @@ 'aphront-drag-and-drop-textarea', array( 'target' => $id, + 'remarkupMetadataID' => $metadata_id, + 'remarkupMetadataValue' => $metadata_value, 'activatedClass' => 'aphront-textarea-drag-and-drop', 'uri' => '/file/dropupload/', 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(), @@ -193,9 +228,7 @@ ), ); - $can_use_macros = - (!$this->disableMacro) && - (function_exists('imagettftext')); + $can_use_macros = function_exists('imagettftext'); if ($can_use_macros) { $can_use_macros = PhabricatorApplication::isClassInstalledForViewer( @@ -353,6 +386,7 @@ array( $buttons, parent::renderInput(), + $metadata_input, )); } diff -Nru phabricator-0~git20200925/phabricator/src/view/page/menu/PhabricatorMainMenuView.php phabricator-0~git20220903/phabricator/src/view/page/menu/PhabricatorMainMenuView.php --- phabricator-0~git20200925/phabricator/src/view/page/menu/PhabricatorMainMenuView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/page/menu/PhabricatorMainMenuView.php 2022-06-14 16:29:55.000000000 +0000 @@ -334,7 +334,7 @@ $wordmark_text = PhabricatorCustomLogoConfigType::getLogoWordmark(); if (!strlen($wordmark_text)) { - $wordmark_text = pht('Phabricator'); + $wordmark_text = PlatformSymbols::getPlatformServerName(); } $wordmark_node = phutil_tag( diff -Nru phabricator-0~git20200925/phabricator/src/view/page/PhabricatorStandardPageView.php phabricator-0~git20220903/phabricator/src/view/page/PhabricatorStandardPageView.php --- phabricator-0~git20200925/phabricator/src/view/page/PhabricatorStandardPageView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/page/PhabricatorStandardPageView.php 2022-06-14 16:29:55.000000000 +0000 @@ -276,7 +276,7 @@ 'doc_name' => pht('See Documentation'), 'doc_href' => $doc_href, 'message' => pht( - 'Phabricator thinks you are using %s, but your '. + 'This server thinks you are using %s, but your '. 'client is convinced that it is using %s. This is a serious '. 'misconfiguration with subtle, but significant, consequences.', $server_protocol, $client_protocol), diff -Nru phabricator-0~git20200925/phabricator/src/view/phui/PHUIColor.php phabricator-0~git20220903/phabricator/src/view/phui/PHUIColor.php --- phabricator-0~git20200925/phabricator/src/view/phui/PHUIColor.php 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/phui/PHUIColor.php 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,13 @@ +<?php + +final class PHUIColor extends Phobject { + + public static function getWebColorFromANSIColor($ansi_color) { + $map = array( + 'cyan' => 'sky', + 'magenta' => 'pink', + ); + + return idx($map, $ansi_color, $ansi_color); + } +} diff -Nru phabricator-0~git20200925/phabricator/src/view/phui/PHUICurtainObjectRefView.php phabricator-0~git20220903/phabricator/src/view/phui/PHUICurtainObjectRefView.php --- phabricator-0~git20200925/phabricator/src/view/phui/PHUICurtainObjectRefView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/phui/PHUICurtainObjectRefView.php 2022-06-14 16:29:55.000000000 +0000 @@ -6,6 +6,8 @@ private $handle; private $epoch; private $highlighted; + private $exiled; + private $exileNote = false; public function setHandle(PhabricatorObjectHandle $handle) { $this->handle = $handle; @@ -22,6 +24,12 @@ return $this; } + public function setExiled($is_exiled, $note = false) { + $this->exiled = $is_exiled; + $this->exileNote = $note; + return $this; + } + protected function getTagAttributes() { $classes = array(); $classes[] = 'phui-curtain-object-ref-view'; @@ -29,6 +37,11 @@ if ($this->highlighted) { $classes[] = 'phui-curtain-object-ref-view-highlighted'; } + + if ($this->exiled) { + $classes[] = 'phui-curtain-object-ref-view-exiled'; + } + $classes = implode(' ', $classes); return array( @@ -60,6 +73,30 @@ $more_rows[] = phutil_tag('tr', array(), $epoch_cells); } + if ($this->exiled) { + if ($this->exileNote !== false) { + $exile_note = $this->exileNote; + } else { + $exile_note = pht('No View Permission'); + } + + $exiled_view = array( + id(new PHUIIconView())->setIcon('fa-eye-slash red'), + ' ', + $exile_note, + ); + + $exiled_cells = array(); + $exiled_cells[] = phutil_tag( + 'td', + array( + 'class' => 'phui-curtain-object-ref-view-exiled-cell', + ), + $exiled_view); + + $more_rows[] = phutil_tag('tr', array(), $exiled_cells); + } + $header_cells = array(); $image_view = $this->newImage(); diff -Nru phabricator-0~git20200925/phabricator/src/view/phui/PHUIHovercardView.php phabricator-0~git20220903/phabricator/src/view/phui/PHUIHovercardView.php --- phabricator-0~git20200925/phabricator/src/view/phui/PHUIHovercardView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/phui/PHUIHovercardView.php 2022-06-14 16:29:55.000000000 +0000 @@ -18,6 +18,7 @@ private $fields = array(); private $actions = array(); private $badges = array(); + private $isExiled; public function setObjectHandle(PhabricatorObjectHandle $handle) { $this->handle = $handle; @@ -43,6 +44,15 @@ return $this; } + public function setIsExiled($is_exiled) { + $this->isExiled = $is_exiled; + return $this; + } + + public function getIsExiled() { + return $this->isExiled; + } + public function addField($label, $value) { $this->fields[] = array( 'label' => $label, diff -Nru phabricator-0~git20200925/phabricator/src/view/phui/PHUIStatusItemView.php phabricator-0~git20220903/phabricator/src/view/phui/PHUIStatusItemView.php --- phabricator-0~git20200925/phabricator/src/view/phui/PHUIStatusItemView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/phui/PHUIStatusItemView.php 2022-06-14 16:29:55.000000000 +0000 @@ -8,6 +8,7 @@ private $target; private $note; private $highlighted; + private $isExiled; const ICON_ACCEPT = 'fa-check-circle'; const ICON_REJECT = 'fa-times-circle'; @@ -46,6 +47,11 @@ return $this; } + public function setIsExiled($is_exiled) { + $this->isExiled = $is_exiled; + return $this; + } + protected function canAppendChild() { return false; } @@ -60,6 +66,10 @@ $classes[] = 'phui-status-item-highlighted'; } + if ($this->isExiled) { + $classes[] = 'phui-status-item-exiled'; + } + return array( 'class' => $classes, ); diff -Nru phabricator-0~git20200925/phabricator/src/view/phui/PHUITagView.php phabricator-0~git20220903/phabricator/src/view/phui/PHUITagView.php --- phabricator-0~git20200925/phabricator/src/view/phui/PHUITagView.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/src/view/phui/PHUITagView.php 2022-06-14 16:29:55.000000000 +0000 @@ -44,6 +44,8 @@ private $shade; private $slimShady; private $border; + private $contextObject; + private $isExiled; public function setType($type) { $this->type = $type; @@ -127,6 +129,24 @@ return strlen($this->href) ? 'a' : 'span'; } + public function setContextObject($context_object) { + $this->contextObject = $context_object; + return $this; + } + + public function getContextObject() { + return $this->contextObject; + } + + public function setIsExiled($is_exiled) { + $this->isExiled = $is_exiled; + return $this; + } + + public function getIsExiled() { + return $this->isExiled; + } + protected function getTagAttributes() { require_celerity_resource('phui-tag-view-css'); @@ -155,6 +175,10 @@ $classes[] = 'phui-tag-'.$this->border; } + if ($this->getIsExiled()) { + $classes[] = 'phui-tag-exiled'; + } + $attributes = array( 'href' => $this->href, 'class' => $classes, @@ -170,10 +194,19 @@ if ($this->phid) { Javelin::initBehavior('phui-hovercards'); + $hovercard_spec = array( + 'objectPHID' => $this->phid, + ); + + $context_object = $this->getContextObject(); + if ($context_object) { + $hovercard_spec['contextPHID'] = $context_object->getPHID(); + } + $attributes += array( 'sigil' => 'hovercard', 'meta' => array( - 'hoverPHID' => $this->phid, + 'hovercardSpec' => $hovercard_spec, ), ); } diff -Nru phabricator-0~git20200925/phabricator/support/startup/PhabricatorStartup.php phabricator-0~git20220903/phabricator/support/startup/PhabricatorStartup.php --- phabricator-0~git20200925/phabricator/support/startup/PhabricatorStartup.php 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/support/startup/PhabricatorStartup.php 2022-06-14 16:29:55.000000000 +0000 @@ -35,6 +35,7 @@ * @task validation Validation * @task ratelimit Rate Limiting * @task phases Startup Phase Timers + * @task request-path Request Path */ final class PhabricatorStartup { @@ -47,6 +48,7 @@ private static $phases; private static $limits = array(); + private static $requestPath; /* -( Accessing Request Information )-------------------------------------- */ @@ -65,7 +67,7 @@ */ public static function getMicrosecondsSinceStart() { // This is the same as "phutil_microseconds_since()", but we may not have - // loaded libphutil yet. + // loaded libraries yet. return (int)(1000000 * (microtime(true) - self::getStartTime())); } @@ -119,6 +121,7 @@ self::$phases = array(); self::$accessLog = null; + self::$requestPath = null; static $registered; if (!$registered) { @@ -140,7 +143,7 @@ self::normalizeInput(); - self::verifyRewriteRules(); + self::readRequestPath(); self::beginOutputCapture(); } @@ -389,14 +392,35 @@ ini_set('memory_limit', -1); // If we have libxml, disable the incredibly dangerous entity loader. + // PHP 8 deprecates this function and disables this by default; remove once + // PHP 7 is no longer supported or a future version has removed the function + // entirely. if (function_exists('libxml_disable_entity_loader')) { - libxml_disable_entity_loader(true); + @libxml_disable_entity_loader(true); } // See T13060. If the locale for this process (the parent process) is not // a UTF-8 locale we can encounter problems when launching subprocesses // which receive UTF-8 parameters in their command line argument list. @setlocale(LC_ALL, 'en_US.UTF-8'); + + $config_map = array( + // See PHI1894. Keep "args" in exception backtraces. + 'zend.exception_ignore_args' => 0, + + // See T13100. We'd like the regex engine to fail, rather than segfault, + // if handed a pathological regular expression. + 'pcre.backtrack_limit' => 10000, + 'pcre.recusion_limit' => 10000, + + // NOTE: Arcanist applies a similar set of startup options for CLI + // environments in "init-script.php". Changes here may also be + // appropriate to apply there. + ); + + foreach ($config_map as $config_key => $config_value) { + ini_set($config_key, $config_value); + } } @@ -518,12 +542,18 @@ "'{$required_version}'."); } - if (@get_magic_quotes_gpc()) { - self::didFatal( - "Your server is configured with PHP 'magic_quotes_gpc' enabled. This ". - "feature is 'highly discouraged' by PHP's developers and you must ". - "disable it to run Phabricator. Consult the PHP manual for ". - "instructions."); + if (function_exists('get_magic_quotes_gpc')) { + if (@get_magic_quotes_gpc()) { + self::didFatal( + 'Your server is configured with the PHP language feature '. + '"magic_quotes_gpc" enabled.'. + "\n\n". + 'This feature is "highly discouraged" by PHP\'s developers, and '. + 'has been removed entirely in PHP8.'. + "\n\n". + 'You must disable "magic_quotes_gpc" to run Phabricator. Consult '. + 'the PHP manual for instructions.'); + } } if (extension_loaded('apc')) { @@ -552,17 +582,29 @@ /** - * @task validation + * @task request-path */ - private static function verifyRewriteRules() { + private static function readRequestPath() { + + // See T13575. The request path may be provided in: + // + // - the "$_GET" parameter "__path__" (normal for Apache and nginx); or + // - the "$_SERVER" parameter "REQUEST_URI" (normal for the PHP builtin + // webserver). + // + // Locate it wherever it is, and store it for later use. Note that writing + // to "$_REQUEST" here won't always work, because later code may rebuild + // "$_REQUEST" from other sources. + if (isset($_REQUEST['__path__']) && strlen($_REQUEST['__path__'])) { + self::setRequestPath($_REQUEST['__path__']); return; } + // Compatibility with PHP 5.4+ built-in web server. if (php_sapi_name() == 'cli-server') { - // Compatibility with PHP 5.4+ built-in web server. - $url = parse_url($_SERVER['REQUEST_URI']); - $_REQUEST['__path__'] = $url['path']; + $path = parse_url($_SERVER['REQUEST_URI']); + self::setRequestPath($path['path']); return; } @@ -580,6 +622,30 @@ } } + /** + * @task request-path + */ + public static function getRequestPath() { + $path = self::$requestPath; + + if ($path === null) { + self::didFatal( + 'Request attempted to access request path, but no request path is '. + 'available for this request. You may be calling web request code '. + 'from a non-request context, or your webserver may not be passing '. + 'a request path to Phabricator in a format that it understands.'); + } + + return $path; + } + + /** + * @task request-path + */ + public static function setRequestPath($path) { + self::$requestPath = $path; + } + /* -( Rate Limiting )------------------------------------------------------ */ diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/differential/revision-history.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/differential/revision-history.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/differential/revision-history.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/differential/revision-history.css 2022-06-14 16:29:55.000000000 +0000 @@ -54,8 +54,3 @@ td.differential-update-history-new { background: #aaffaa; } - -.lintunit-star { - text-align: center; - padding: 0 16px; -} diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/herald/herald-test.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/herald/herald-test.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/herald/herald-test.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/herald/herald-test.css 2022-06-14 16:29:55.000000000 +0000 @@ -4,6 +4,8 @@ .herald-condition-note { color: {$red}; + padding: 4px 0; + margin: 4px 0 8px; } textarea.herald-field-value-transcript { diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/project/project-card-view.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/project/project-card-view.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/project/project-card-view.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/project/project-card-view.css 2022-06-14 16:29:55.000000000 +0000 @@ -72,6 +72,17 @@ color: {$greytext}; } +.project-card-view .project-card-item-exiled { + background-color: {$lightredbackground}; + border-radius: 4px; + padding: 2px 8px; + margin: 2px 0; +} + +.project-card-view .project-card-item-exiled .project-card-item-text { + color: {$red}; +} + .project-card-view .project-card-item-icon { width: 20px; } diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-core.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-core.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-core.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-core.css 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/** - * @provides releeph-core - */ - - -/* Colors: match differential colors */ - -.releeph-request-comment { - border-color: #ddd; -} - -.releeph-request-comment-pusher { - background: #8DEE8D; - border-color: #096; -} - -.releeph-request-comment-pusher div { - background: #8DEE8D; -} - -/* The diff size bar */ - -.diff-bar { - border: 0px; -} - -.diff-bar div { - width: 100px; - border: 1px solid; - border-top-color: #A4A4A4; - border-right-color: #BBB; - border-bottom-color: #D5D5D5; - border-left-color: #BBB; - background: white; - float: left; - margin-right: 1em; -} - -.diff-bar div div { - height: 10px; -} - -.diff-bar span { - color: #555; -} diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-preview-branch.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-preview-branch.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-preview-branch.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-preview-branch.css 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/** - * @provides releeph-preview-branch - */ - -.releeph-preview-branch { - min-height: 4em; - position: relative; -} - -.releeph-preview-branch .error { - padding-left: 22px; - background-repeat: no-repeat; - background-size: 16px auto; - float: left; - position: absolute; - top: 2.5em; - - /* TODO: This had a background that's still at Facebook? */ -} - -.releeph-preview-branch .name { - clear: both; - float: left; - position: absolute; - font-family: monospace; - font-size: 9pt !important; - background: white; - top: 0.7em; - padding: 2px; -} diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-request-differential-create-dialog.css 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -/** - * @provides releeph-request-differential-create-dialog - */ - -.releeph-request-differential-create-dialog h1 { - color: gray; - font-style: italic; - font-size: 16px; - margin-top: 0.8em; -} - -.releeph-request-differential-create-dialog a { - font-weight: bold; - margin-left: 2em; - display: block; - margin-top: 1em; -} diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-request-typeahead.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-request-typeahead.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/application/releeph/releeph-request-typeahead.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/application/releeph/releeph-request-typeahead.css 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/** - * @provides releeph-request-typeahead-css - */ - -.releeph-request-typeahead .commit-id { - color: #aaf; /* blue... */ - font-family: monospace; - font-size: 100%; - display: block; - float: left; -} - -.releeph-request-typeahead .author-info { - color: #080; /* ...and green, for search results! */ - text-align: right; - display: block; - float: right; - padding-left: 1em; -} - -.releeph-request-typeahead .focused .author-info { - color: #8b8; -} - -.releeph-request-typeahead .summary { - clear: both; -} diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/core/remarkup.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/core/remarkup.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/core/remarkup.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/core/remarkup.css 2022-06-14 16:29:55.000000000 +0000 @@ -86,11 +86,6 @@ padding: 1px 4px; border-radius: 3px; white-space: pre-wrap; - - /* See T13564. This is a narrow control for PDF printing behavior in - Chrome. */ - line-break: anywhere; - overflow-wrap: anywhere; } /* NOTE: You can currently produce this with [[link | `name`]]. Restore the @@ -296,11 +291,6 @@ color: {$greytext}; } -.phabricator-remarkup-mention-nopermission .phui-tag-core { - background: {$lightgreybackground}; - color: {$lightgreytext}; -} - .phabricator-remarkup .remarkup-note { margin: 16px 0; padding: 12px; @@ -499,6 +489,10 @@ overflow-x: auto; } +!print .phabricator-remarkup .remarkup-table-wrap { + overflow-x: hidden; +} + .phabricator-remarkup table.remarkup-table { border-collapse: separate; border-spacing: 1px; @@ -518,6 +512,14 @@ padding: 3px 6px; } +!print .phabricator-remarkup table.remarkup-table td { + /* See T13564. This is a narrow control for PDF printing behavior in + Chrome. */ + + line-break: anywhere; + overflow-wrap: anywhere; +} + body div.phabricator-remarkup.remarkup-has-toc .phabricator-remarkup-toc + .remarkup-header { margin-top: 0; diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css 2022-06-14 16:29:55.000000000 +0000 @@ -12,6 +12,10 @@ border-radius: 3px; } +.phui-curtain-object-ref-view + .phui-curtain-object-ref-view { + margin-top: 1px; +} + .phui-curtain-object-ref-view-image-cell { min-width: 32px; padding-bottom: 24px; @@ -82,3 +86,13 @@ .phui-curtain-object-ref-view-highlighted { background: {$bluebackground}; } + +.phui-curtain-object-ref-view-exiled { + background: {$lightred}; + opacity: 0.75; +} + +.phui-curtain-object-ref-view-exiled-cell, +.phui-curtain-object-ref-view-exiled-cell a { + color: {$red}; +} diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-list.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-list.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-list.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-list.css 2022-06-14 16:29:55.000000000 +0000 @@ -75,11 +75,10 @@ padding: 4px 10px; } -.phui-list-sidenav .phui-list-item-has-icon .phui-list-item-indented { - padding-left: 18px; +.phabricator-side-menu .phui-list-item-has-icon .phui-list-item-indented { + padding-left: 24px; } - .device-desktop .phui-list-sidenav .phui-list-item-href:hover { background: {$sky}; color: white; diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-status.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-status.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-status.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-status.css 2022-06-14 16:29:55.000000000 +0000 @@ -29,10 +29,16 @@ border-radius: 3px; } +.phui-status-item-exiled td { + background-color: {$lightredbackground}; + border-radius: 3px; +} + .phui-status-list-view td a { color: {$darkbluetext}; } -.phui-status-item-highlighted td.phui-status-item-note { +.phui-status-item-highlighted td.phui-status-item-note, +.phui-status-item-exiled td.phui-status-item-note { background-color: transparent; } diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-tag-view.css phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-tag-view.css --- phabricator-0~git20200925/phabricator/webroot/rsrc/css/phui/phui-tag-view.css 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/css/phui/phui-tag-view.css 2022-06-14 16:29:55.000000000 +0000 @@ -531,3 +531,15 @@ color: {$blacktext}; border-color: {$blacktext}; } + +.phui-tag-exiled .phui-tag-core { + border-color: {$lightredborder}; + color: {$red}; + background: {$lightredbackground}; +} + + +a.phui-tag-view.phui-tag-exiled:hover + .phui-tag-core.phui-tag-color-person { + border-color: {$red}; +} diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner --- phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/docs/concepts/behaviors.diviner 2022-06-14 16:29:55.000000000 +0000 @@ -124,7 +124,7 @@ the full power of arbitrary JS execution. - It's utterly hideous. -In 2007/2008, we introduced @{function@libphutil:jsprintf} and a function called +In 2007/2008, we introduced @{function@arcanist:jsprintf} and a function called onloadRegister() to solve some of the obvious problems: lang=php diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/docs/facebook.diviner phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/docs/facebook.diviner --- phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/docs/facebook.diviner 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/docs/facebook.diviner 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -@title Javelin at Facebook -@group facebook - -Information specific to Javelin at Facebook. - -= Building Support Scripts = - -Javelin now ships with the source to build several libfbjs-based binaries, which -serve to completely sever its dependencies on trunk: - - - `javelinsymbols`: used for lint - - `jsast`: used for documentation generation - - `jsxmin`: used to crush packages - -To build these, first build libfbjs: - - javelin/ $ cd externals/libfbjs - javelin/externals/libfbjs/ $ CXX=/usr/bin/g++ make - -Note that **you must specify CXX explicitly because the default CXX is broken**. - -Now you should be able to build the individual binaries: - - javelin/ $ cd support/javelinsymbols - javelin/support/javelinsymbols $ CXX=/usr/bin/g++ make - - javelin/ $ cd support/jsast - javelin/support/jsast $ CXX=/usr/bin/g++ make - - javelin/ $ cd support/jsxmin - javelin/support/jsxmin $ CXX=/usr/bin/g++ make - -= Synchronizing Javelin = - -To synchronize Javelin **from** Facebook trunk, run the synchronize script: - - javelin/ $ ./scripts/sync-from-facebook.php ~/www - -...where `~/www` is the root you want to pull Javelin files from. The script -will copy files out of `html/js/javelin` and build packages, and leave the -results in your working copy. From there you can review changes and commit, and -then push, diff, or send a pull request. - -To synchronize Javelin **to** Facebook trunk, run the, uh, reverse-synchronize -script: - - javelin/ $ ./scripts/sync-to-facebook.php ~/www - -...where `~/www` is the root you want to push Javelin files to. The script -will copy files out of the working copy into your `www` and leave you with a -dirty `www`. From there you can review changes. - -Once Facebook moves to pure git for `www` we can probably just submodule -Javelin into it and get rid of all this nonsense, but the mixed SVN/git -environment makes that difficult until then. - -= Building Documentation = - -Check out `diviner` and `libphutil` from Facebook github, and put them in a -directory with `javelin`: - - somewhere/ $ ls - diviner/ - javelin/ - libphutil/ - somewhere/ $ - -Now run `diviner` on `javelin`: - - somewhere/ $ cd javelin - somewhere/javelin/ $ ../diviner/bin/diviner . - [DivinerArticleEngine] Generating documentation for 48 files... - [JavelinDivinerEngine] Generating documentation for 74 files... - somewhere/javelin/ $ - -Documentation is now available in `javelin/docs/`. - -= Editing javelinjs.com = - -The source for javelinjs.com lives in `javelin/support/webroot/`. The site -itself is served off the phabricator.com host. You need access to that host to -push it. diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/lib/DOM.js phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/lib/DOM.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/lib/DOM.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/lib/DOM.js 2022-06-14 16:29:55.000000000 +0000 @@ -124,7 +124,7 @@ 'will not do the right thing with this.'); } - // TODO(epriestley): May need to deny <option> more broadly, see + // TODO: May need to deny <option> more broadly, see // http://support.microsoft.com/kb/829907 and the whole mess in the // heavy stack. But I seem to have gotten away without cloning into the // documentFragment below, so this may be a nonissue. @@ -147,7 +147,7 @@ wrapper.innerHTML = this._content; var fragment = document.createDocumentFragment(); while (wrapper.firstChild) { - // TODO(epriestley): Do we need to do a bunch of cloning junk here? + // TODO: Do we need to do a bunch of cloning junk here? // See heavy stack. I'm disconnecting the nodes instead; this seems // to work but maybe my test case just isn't extensive enough. fragment.appendChild(wrapper.removeChild(wrapper.firstChild)); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/lib/Resource.js phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/lib/Resource.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/externals/javelin/lib/Resource.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/externals/javelin/lib/Resource.js 2022-06-14 16:29:55.000000000 +0000 @@ -149,6 +149,10 @@ } } + for (var jj = 0; jj < errors.length; jj++) { + JX.log(errors[jj]); + } + if (errors.length) { throw errors[0]; } diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diff/DiffChangeset.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diff/DiffChangeset.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diff/DiffChangeset.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diff/DiffChangeset.js 2022-06-14 16:29:55.000000000 +0000 @@ -671,9 +671,6 @@ // Code shared by autoload and context responses. this._loadChangesetState(response); - - JX.Stratcom.invoke('differential-inline-comment-refresh'); - this._rebuildAllInlines(); JX.Stratcom.invoke('resize'); @@ -723,16 +720,19 @@ var data = JX.Stratcom.getData(node); if (!data.inline) { - var inline = new JX.DiffInline() - .setChangeset(this) - .bindToRow(node); - - this._inlines.push(inline); + var inline = this._newInlineForRow(node); + this.getInlines().push(inline); } return data.inline; }, + _newInlineForRow: function(node) { + return new JX.DiffInline() + .setChangeset(this) + .bindToRow(node); + }, + newInlineForRange: function(origin, target, options) { var list = this.getChangesetList(); @@ -770,7 +770,7 @@ .setChangeset(this) .bindToRange(data); - this._inlines.push(inline); + this.getInlines().push(inline); inline.create(); @@ -843,9 +843,7 @@ }, _rebuildAllInlines: function() { - if (this._inlines === null) { - this._inlines = []; - } + this._inlines = []; var rows = JX.DOM.scry(this._node, 'tr'); var ii; @@ -855,9 +853,7 @@ continue; } - // As a side effect, this builds any missing inline objects and adds - // them to this Changeset's list of inlines. - this.getInlineForRow(row); + this._inlines.push(this._newInlineForRow(row)); } }, diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diff/DiffInlineContentState.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diff/DiffInlineContentState.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diff/DiffInlineContentState.js 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diff/DiffInlineContentState.js 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,137 @@ +/** + * @provides phabricator-diff-inline-content-state + * @requires javelin-dom + * @javelin + */ + +JX.install('DiffInlineContentState', { + + construct : function() { + + }, + + properties: { + text: null, + suggestionText: null, + hasSuggestion: false + }, + + members: { + readForm: function(row) { + var node; + + try { + node = JX.DOM.find(row, 'textarea', 'inline-content-text'); + this.setText(node.value); + } catch (ex) { + this.setText(null); + } + + node = this._getSuggestionNode(row); + if (node) { + this.setSuggestionText(node.value); + } else { + this.setSuggestionText(null); + } + + return this; + }, + + getWireFormat: function() { + return { + text: this.getText(), + suggestionText: this.getSuggestionText(), + hasSuggestion: this.getHasSuggestion() + }; + }, + + readWireFormat: function(map) { + this.setText(map.text || null); + this.setSuggestionText(map.suggestionText || null); + this.setHasSuggestion(!!map.hasSuggestion); + + return this; + }, + + getTextForQuote: function() { + var text = this.getText(); + text = '> ' + text.replace(/\n/g, '\n> ') + '\n\n'; + return text; + }, + + isStateEmpty: function() { + return (this.isTextEmpty() && this.isSuggestionEmpty()); + }, + + isTextEmpty: function() { + var text = this.getText(); + if (text === null) { + return true; + } + + if (this._isStringSimilar(text, '')) { + return true; + } + + return false; + }, + + isSuggestionEmpty: function() { + if (!this.getHasSuggestion()) { + return true; + } + + var suggestion = this.getSuggestionText(); + if (suggestion === null) { + return true; + } + + if (this._isStringSimilar(suggestion, '')) { + return true; + } + + return false; + }, + + isTextSimilar: function(v) { + if (!v) { + return false; + } + + var us = this.getText(); + var vs = v.getText(); + + return this._isStringSimilar(us, vs); + }, + + isSuggestionSimilar: function(v) { + // If we don't have a comparison state, treat them as dissimilar. This + // is expected to occur in old inline comments that did not save an + // initial state. + + if (!v) { + return false; + } + + var us = this.getSuggestionText(); + var vs = v.getSuggestionText(); + + return this._isStringSimilar(us, vs); + }, + + _isStringSimilar: function(u, v) { + u = u || ''; + v = v || ''; + return (u === v); + }, + + _getSuggestionNode: function(row) { + try { + return JX.DOM.find(row, 'textarea', 'inline-content-suggestion'); + } catch (ex) { + return null; + } + } + } + +}); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diff/DiffInline.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diff/DiffInline.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diff/DiffInline.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diff/DiffInline.js 2022-06-14 16:29:55.000000000 +0000 @@ -1,12 +1,14 @@ /** * @provides phabricator-diff-inline * @requires javelin-dom + * phabricator-diff-inline-content-state * @javelin */ JX.install('DiffInline', { construct : function() { + this._state = {}; }, members: { @@ -19,7 +21,6 @@ _displaySide: null, _isNewFile: null, _replyToCommentPHID: null, - _originalState: null, _snippet: null, _menuItems: null, _documentEngineKey: null, @@ -53,6 +54,8 @@ _isSelected: false, _canSuggestEdit: false, + _state: null, + bindToRow: function(row) { this._row = row; @@ -323,8 +326,6 @@ this._phid = null; this._isCollapsed = false; - this._originalState = null; - return row; }, @@ -412,25 +413,12 @@ .send(); }, - _getContentState: function() { - var state; - - if (this._editRow) { - state = this._readFormState(this._editRow); - } else { - state = this._originalState; - } - - return state; - }, - reply: function(with_quote) { this._closeMenu(); var content_state = this._newContentState(); if (with_quote) { - var text = this._getContentState().text; - text = '> ' + text.replace(/\n/g, '\n> ') + '\n\n'; + var text = this._getActiveContentState().getTextForQuote(); content_state.text = text; } @@ -455,21 +443,12 @@ this._undoText = null; } - var uri = this._getInlineURI(); - var handler = JX.bind(this, this._oneditresponse); - - var data = this._newRequestData('edit', content_state); - - this.setLoading(true); - - new JX.Request(uri, handler) - .setData(data) - .send(); + this._applyEdit(content_state); }, delete: function(is_ref) { var uri = this._getInlineURI(); - var handler = JX.bind(this, this._ondeleteresponse); + var handler = JX.bind(this, this._ondeleteresponse, false); // NOTE: This may be a direct delete (the user clicked on the inline // itself) or a "refdelete" (the user clicked somewhere else, like the @@ -589,7 +568,6 @@ this._readInlineState(response.inline); this._drawEditRows(rows); - this.setLoading(false); this.setInvisible(true); }, @@ -602,28 +580,44 @@ _readInlineState: function(state) { this._id = state.id; - this._originalState = state.contentState; + + this._state = { + initial: this._newContentStateFromWireFormat(state.state.initial), + committed: this._newContentStateFromWireFormat(state.state.committed), + active: this._newContentStateFromWireFormat(state.state.active) + }; + this._canSuggestEdit = state.canSuggestEdit; }, - _ondeleteresponse: function() { - // If there's an existing "unedit" undo element, remove it. - if (this._undoRow) { - JX.DOM.remove(this._undoRow); - this._undoRow = null; + _newContentStateFromWireFormat: function(map) { + if (map === null) { + return null; } - // If there's an existing editor, remove it. This happens when you - // delete a comment from the comment preview area. In this case, we - // read and preserve the text so "Undo" restores it. - var state = null; - if (this._editRow) { - state = this._readFormState(this._editRow); - JX.DOM.remove(this._editRow); - this._editRow = null; - } + return new JX.DiffInlineContentState().readWireFormat(map); + }, - this._drawUndeleteRows(state); + _ondeleteresponse: function(prevent_undo) { + if (!prevent_undo) { + // If there's an existing "unedit" undo element, remove it. + if (this._undoRow) { + JX.DOM.remove(this._undoRow); + this._undoRow = null; + } + + // If there's an existing editor, remove it. This happens when you + // delete a comment from the comment preview area. In this case, we + // read and preserve the text so "Undo" restores it. + var state = null; + if (this._editRow) { + state = this._getActiveContentState().getWireFormat(); + JX.DOM.remove(this._editRow); + this._editRow = null; + } + + this._drawUndeleteRows(state); + } this.setLoading(false); this.setDeleted(true); @@ -668,7 +662,10 @@ this._editRow = this._drawRows(rows, null, 'edit'); this._drawSuggestionState(this._editRow); - this.setHasSuggestion(this._originalState.hasSuggestion); + + // TODO: We're just doing this for the rendering side effect of drawing + // the button text. + this.setHasSuggestion(this.getHasSuggestion()); }, _drawRows: function(rows, cursor, type) { @@ -677,7 +674,6 @@ var anchor = cursor || this._row; cursor = cursor || this._row.nextSibling; - var result_row; var next_row; while (row) { @@ -762,21 +758,12 @@ this.setHasSuggestion(!this.getHasSuggestion()); - // The first time the user actually clicks the button and enables - // suggestions for a given editor state, fill the input with the - // underlying text if there isn't any text yet. + // Resize the suggestion input for size of the text. if (this.getHasSuggestion()) { if (this._editRow) { var node = this._getSuggestionNode(this._editRow); if (node) { - if (!node.value.length) { - var data = JX.Stratcom.getData(node); - if (!data.hasSetDefault) { - data.hasSetDefault = true; - node.value = data.defaultText; - node.rows = Math.max(3, node.value.split('\n').length); - } - } + node.rows = Math.max(3, node.value.split('\n').length); } } } @@ -785,8 +772,27 @@ this.triggerDraft(); }, + _getActiveContentState: function() { + var state = this._state.active; + + if (this._editRow) { + state.readForm(this._editRow); + } + + return state; + }, + + _getCommittedContentState: function() { + return this._state.committed; + }, + + _getInitialContentState: function() { + return this._state.initial; + }, + setHasSuggestion: function(has_suggestion) { - this._hasSuggestion = has_suggestion; + var state = this._getActiveContentState(); + state.setHasSuggestion(has_suggestion); var button = this._getSuggestionButton(); var pht = this.getChangeset().getChangesetList().getTranslations(); @@ -806,20 +812,121 @@ }, getHasSuggestion: function() { - return this._hasSuggestion; + return this._getActiveContentState().getHasSuggestion(); }, save: function() { - var handler = JX.bind(this, this._onsubmitresponse); + if (this._shouldDeleteOnSave()) { + JX.DOM.remove(this._editRow); + this._editRow = null; - this.setLoading(true); + this._applyDelete(true); + return; + } + + this._applySave(); + }, + + _shouldDeleteOnSave: function() { + var active = this._getActiveContentState(); + var initial = this._getInitialContentState(); + + // When a user clicks "Save", it counts as a "delete" if the content + // of the comment is functionally empty. + + // This isn't a delete if there's any text. Even if the text is a + // quote (so the state is the same as the initial state), we preserve + // it when the user clicks "Save". + if (!active.isTextEmpty()) { + return false; + } + + // This isn't a delete if there's a suggestion and that suggestion is + // different from the initial state. (This means that an inline which + // purely suggests a block of code should be deleted is non-empty.) + if (active.getHasSuggestion()) { + if (!active.isSuggestionSimilar(initial)) { + return false; + } + } + + // Otherwise, this comment is functionally empty, so we can just treat + // a "Save" as a "delete". + return true; + }, + + _shouldUndoOnCancel: function() { + var committed = this._getCommittedContentState(); + var active = this._getActiveContentState(); + var initial = this._getInitialContentState(); + + // When a user clicks "Cancel", we only offer to let them "Undo" the + // action if the undo would be substantive. + + // The undo is substantive if the text is nonempty, and not similar to + // the last state. + var versus = committed || initial; + if (!active.isTextEmpty() && !active.isTextSimilar(versus)) { + return true; + } + + // The undo is substantive if there's a suggestion, and the suggestion + // is not similar to the last state. + if (active.getHasSuggestion()) { + if (!active.isSuggestionSimilar(versus)) { + return true; + } + } + + return false; + }, + + _applySave: function() { + var handler = JX.bind(this, this._onsaveresponse); + var state = this._getActiveContentState(); + var data = this._newRequestData('save', state.getWireFormat()); + + this._applyCall(handler, data); + }, + + _applyDelete: function(prevent_undo) { + var handler = JX.bind(this, this._ondeleteresponse, prevent_undo); + + var data = this._newRequestData('delete'); + + this._applyCall(handler, data); + }, + + _applyCancel: function(state) { + var handler = JX.bind(this, this._onCancelResponse); + + var data = this._newRequestData('cancel', state); + + this._applyCall(handler, data); + }, + + _applyEdit: function(state) { + var handler = JX.bind(this, this._oneditresponse); + + var data = this._newRequestData('edit', state); + + this._applyCall(handler, data); + }, + + _applyCall: function(handler, data) { var uri = this._getInlineURI(); - var data = this._newRequestData('save', this._getContentState()); - new JX.Request(uri, handler) - .setData(data) - .send(); + var callback = JX.bind(this, function() { + this.setLoading(false); + handler.apply(null, arguments); + }); + + this.setLoading(true); + + new JX.Workflow(uri, data) + .setHandler(callback) + .start(); }, undo: function() { @@ -850,79 +957,45 @@ }, cancel: function() { - var state = this._readFormState(this._editRow); + // NOTE: Read the state before we remove the editor. Otherwise, we might + // miss text the user has entered into the textarea. + var state = this._getActiveContentState().getWireFormat(); JX.DOM.remove(this._editRow); this._editRow = null; - var is_empty = this._isVoidContentState(state); - var is_same = this._isSameContentState(state, this._originalState); - if (!is_empty && !is_same) { - this._drawUneditRows(state); - } + // When a user clicks "Cancel", we delete the comment if it has never + // been saved: we don't have a non-empty display state to revert to. + var is_delete = (this._getCommittedContentState() === null); - // If this was an empty box and we typed some text and then hit cancel, - // don't show the empty concrete inline. - if (this._isVoidContentState(this._originalState)) { - this.setInvisible(true); - } else { - this.setInvisible(false); - } + var is_undo = this._shouldUndoOnCancel(); // If you "undo" to restore text ("AB") and then "Cancel", we put you // back in the original text state ("A"). We also send the original // text ("A") to the server as the current persistent state. - var uri = this._getInlineURI(); - var data = this._newRequestData('cancel', this._originalState); - var handler = JX.bind(this, this._onCancelResponse); - - this.setLoading(true); - - new JX.Request(uri, handler) - .setData(data) - .send(); - - this._didUpdate(true); - }, - - _onCancelResponse: function(response) { - this.setEditing(false); - this.setLoading(false); - - // If the comment was empty when we started editing it (there's no - // original text) and empty when we finished editing it (there's no - // undo row), just delete the comment. - if (this._isVoidContentState(this._originalState) && !this.isUndo()) { - this.setDeleted(true); - - JX.DOM.remove(this._row); - this._row = null; - - this._didUpdate(); + if (is_undo) { + this._drawUneditRows(state); } - }, - _readFormState: function(row) { - var state = this._newContentState(); + if (is_delete) { + // NOTE: We're always suppressing the undo from "delete". We want to + // use the "undo" we just added above instead, which will get us + // back to the ephemeral, client-side editor state. + this._applyDelete(true); + } else { + this.setEditing(false); + this.setInvisible(false); - var node; + var old_state = this._getCommittedContentState(); + this._applyCancel(old_state.getWireFormat()); - try { - node = JX.DOM.find(row, 'textarea', 'inline-content-text'); - state.text = node.value; - } catch (ex) { - // Ignore. - } - - node = this._getSuggestionNode(row); - if (node) { - state.suggestionText = node.value; + this._didUpdate(true); } + }, - state.hasSuggestion = this.getHasSuggestion(); - - return state; + _onCancelResponse: function(response) { + // Nothing to do. }, _getSuggestionNode: function(row) { @@ -933,40 +1006,18 @@ } }, - _onsubmitresponse: function(response) { + _onsaveresponse: function(response) { if (this._editRow) { JX.DOM.remove(this._editRow); this._editRow = null; } - this.setLoading(false); - this.setInvisible(false); this.setEditing(false); + this.setInvisible(false); - this._onupdate(response); - }, - - _onupdate: function(response) { - var new_row; - if (response.view) { - new_row = this._drawContentRows(JX.$H(response.view).getNode()); - } - - // TODO: Save the old row so the action it's undo-able if it was a - // delete. - var remove_old = true; - if (remove_old) { - JX.DOM.remove(this._row); - } - - // If you delete the content on a comment and save it, it acts like a - // delete: the server does not return a new row. - if (new_row) { - this.bindToRow(new_row); - } else { - this.setDeleted(true); - this._row = null; - } + var new_row = this._drawContentRows(JX.$H(response.view).getNode()); + JX.DOM.remove(this._row); + this.bindToRow(new_row); this._didUpdate(); }, @@ -1037,8 +1088,8 @@ return null; } - var state = this._readFormState(this._editRow); - if (this._isVoidContentState(state)) { + var state = this._getActiveContentState(); + if (state.isStateEmpty()) { return null; } @@ -1047,7 +1098,7 @@ id: this.getID(), }; - JX.copy(draft_data, state); + JX.copy(draft_data, state.getWireFormat()); return draft_data; }, @@ -1163,19 +1214,8 @@ suggestionText: '', hasSuggestion: false }; - }, - - _isVoidContentState: function(state) { - return (!state.text.length && !state.suggestionText.length); - }, - - _isSameContentState: function(u, v) { - return ( - ((u === null) === (v === null)) && - (u.text === v.text) && - (u.suggestionText === v.suggestionText) && - (u.hasSuggestion === v.hasSuggestion)); } + } }); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diffusion/behavior-commit-graph.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diffusion/behavior-commit-graph.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/diffusion/behavior-commit-graph.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/diffusion/behavior-commit-graph.js 2022-06-14 16:29:55.000000000 +0000 @@ -62,10 +62,10 @@ }; var h; - if (config.autoheight) { - h = JX.Vector.getDim(nodes[ii].parentNode).y; + if (config.height) { + h = config.height; } else { - h = 34; + h = JX.Vector.getDim(nodes[ii].parentNode).y; } var w = cell * config.count; diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/releeph/releeph-preview-branch.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/releeph/releeph-preview-branch.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/releeph/releeph-preview-branch.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/releeph/releeph-preview-branch.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/** - * @provides javelin-behavior-releeph-preview-branch - * @requires javelin-behavior - * javelin-dom - * javelin-uri - * javelin-request - */ - -JX.behavior('releeph-preview-branch', function(config) { - - var uri = JX.$U(config.uri); - for (var param_name in config.params.static) { - var value = config.params.static[param_name]; - uri.setQueryParam(param_name, value); - } - - var output = JX.$(config.outputID); - - var dynamics = config.params.dynamic; - - function renderPreview() { - for (var param_name in dynamics) { - var node_id = dynamics[param_name]; - var input = JX.$(node_id); - uri.setQueryParam(param_name, input.value); - } - var request = new JX.Request(uri, function(response) { - JX.DOM.setContent(output, JX.$H(response.markup)); - }); - request.send(); - } - - renderPreview(); - - for (var ii in dynamics) { - var node_id = dynamics[ii]; - var input = JX.$(node_id); - JX.DOM.listen( - input, - ['keyup', 'click', 'change'], - null, - function() { - renderPreview(); - } - ); - } - -}); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/releeph/releeph-request-state-change.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/releeph/releeph-request-state-change.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/releeph/releeph-request-state-change.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/releeph/releeph-request-state-change.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -/** - * @provides javelin-behavior-releeph-request-state-change - * @requires javelin-behavior - * javelin-dom - * javelin-stratcom - * javelin-workflow - * javelin-util - * phabricator-keyboard-shortcut - */ - -JX.behavior('releeph-request-state-change', function() { - function getRequestHeaderNodes() { - return JX.DOM.scry(document.body, 'div', 'releeph-request-box'); - } - - var keynav_cursor = -1; - - function keynavJump(manager, delta) { - // Calculate this everytime, because the DOM changes. - var headers = getRequestHeaderNodes(); - keynav_cursor += delta; - - if (keynav_cursor < 0) { - keynav_cursor = -1; - JX.DOM.scrollToPosition(0, 0); - keynavMarkup(); - return; - } - - if (keynav_cursor >= headers.length) { - keynav_cursor = headers.length - 1; - } - - var focus = headers[keynav_cursor]; - manager.scrollTo(focus); - - keynavMarkup(); - } - - function keynavMarkup() { - var headers = getRequestHeaderNodes(); - for (var k in headers) { - JX.DOM.alterClass(headers[k], 'focus', k == keynav_cursor); - } - } - - function keynavAction(manager, action_name) { - var headers = getRequestHeaderNodes(); - var header = headers[keynav_cursor]; - - if (keynav_cursor < 0) { - return; - } - - var sigil = action_name; - var button = JX.DOM.find(header, 'a', sigil); - if (button) { - button.click(); - } - } - - function keynavNavigateToRequestPage() { - var headers = getRequestHeaderNodes(); - var header = headers[keynav_cursor]; - window.open(JX.Stratcom.getData(header).uri); - } - - new JX.KeyboardShortcut('j', 'Jump to next request.') - .setHandler(function(manager) { - keynavJump(manager, +1); - }) - .register(); - - new JX.KeyboardShortcut('k', 'Jump to previous request.') - .setHandler(function(manager) { - keynavJump(manager, -1); - }) - .register(); - - new JX.KeyboardShortcut('a', 'Approve the selected request.') - .setHandler(function(manager) { - keynavAction(manager, 'want'); - }) - .register(); - - new JX.KeyboardShortcut('r', 'Reject the selected request.') - .setHandler(function(manager) { - keynavAction(manager, 'pass'); - }) - .register(); - - new JX.KeyboardShortcut( - ['g', 'return'], - 'Open selected request\'s page in a new tab.') - .setHandler(function() { - keynavNavigateToRequestPage(); - }) - .register(); - - function onresponse(box, response) { - JX.DOM.replace(box, JX.$H(response.markup)); - keynavMarkup(); - } - - JX.Stratcom.listen( - 'click', - 'releeph-request-state-change', - function(e) { - e.kill(); - - var box = e.getNode('releeph-request-box'); - var link = e.getNode('releeph-request-state-change'); - - box.style.opacity = '0.5'; - - JX.Workflow.newFromLink(link) - .setData({render: true}) - .setHandler(JX.bind(null, onresponse, box)) - .start(); - }); -}); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/releeph/releeph-request-typeahead.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/releeph/releeph-request-typeahead.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/releeph/releeph-request-typeahead.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/releeph/releeph-request-typeahead.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/** - * @provides javelin-behavior-releeph-request-typeahead - * @requires javelin-behavior - * javelin-dom - * javelin-typeahead - * javelin-typeahead-ondemand-source - * javelin-dom - */ - -JX.behavior('releeph-request-typeahead', function(config) { - var root = JX.$(config.id); - var datasource = new JX.TypeaheadOnDemandSource(config.src); - var callsign = config.aux.callsign; - - datasource.setAuxiliaryData(config.aux); - - datasource.setTransformer( - function(object) { - var full_commit_id = object[0]; - var short_commit_id = object[1]; - var author = object[2]; - var ago = object[3]; - var summary = object[4]; - - var callsign_commit_id = 'r' + callsign + short_commit_id; - - var box = - JX.$N( - 'div', - {}, - [ - JX.$N( - 'div', - { className: 'commit-id' }, - callsign_commit_id - ), - JX.$N( - 'div', - { className: 'author-info' }, - ago + ' ago by ' + author - ), - JX.$N( - 'div', - { className: 'summary' }, - summary - ) - ] - ); - - return { - name: callsign_commit_id, - tokenizable: callsign_commit_id + ' '+ short_commit_id + ' ' + summary, - display: box, - uri: null, - id: full_commit_id - }; - }); - - /** - * The default normalizer removes useful control characters that would help - * out search. For example, I was just trying to search for a commit with - * the string "a_file" in the message, which was normalized to "afile". - */ - datasource.setNormalizer(function(query) { - return query; - }); - - datasource.setMaximumResultCount(config.aux.limit); - - var typeahead = new JX.Typeahead(root); - typeahead.setDatasource(datasource); - - var placeholder = config.value || config.placeholder; - if (placeholder) { - typeahead.setPlaceholder(placeholder); - } - - typeahead.start(); -}); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/repository/repository-crossreference.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/repository/repository-crossreference.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/application/repository/repository-crossreference.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/application/repository/repository-crossreference.js 2022-06-14 16:29:55.000000000 +0000 @@ -66,13 +66,8 @@ var target = e.getTarget(); - try { - // If we're in an inline comment, don't link symbols. - if (JX.DOM.findAbove(target, 'div', 'differential-inline-comment')) { - return; - } - } catch (ex) { - // Continue if we're not inside an inline comment. + if (!canLinkNode(target)) { + return; } // If only part of the symbol was edited, the symbol name itself will @@ -97,6 +92,29 @@ } }); } + + function canLinkNode(node) { + try { + // If we're in an inline comment, don't link symbols. + if (JX.DOM.findAbove(node, 'div', 'differential-inline-comment')) { + return false; + } + } catch (ex) { + // Continue if we're not inside an inline comment. + } + + // See T13644. Don't open symbols if we're inside a changeset header. + try { + if (JX.DOM.findAbove(node, 'h1')) { + return false; + } + } catch (ex) { + // Continue if not inside a header. + } + + return true; + } + function unhighlight() { highlighted && JX.DOM.alterClass(highlighted, classHighlight, false); highlighted = null; @@ -159,6 +177,9 @@ uri_symbol = uri_symbol.trim(); // See T13437. Symbols like "#define" need to be encoded. + // See T13644. Symbols like "a/b" must be double-encoded to survive + // one layer of decoding by the webserver. + uri_symbol = encodeURIComponent(uri_symbol); uri_symbol = encodeURIComponent(uri_symbol); var uri = JX.$U('/diffusion/symbol/' + uri_symbol + '/'); @@ -223,7 +244,7 @@ var changeset; try { changeset = JX.DOM.findAbove(target, 'div', 'differential-changeset'); - return JX.Stratcom.getData(changeset).path; + return JX.Stratcom.getData(changeset).symbolPath || null; } catch (ex) { // Ignore. } @@ -315,13 +336,8 @@ var target = e.getTarget(); - try { - // If we're in an inline comment, don't link symbols. - if (JX.DOM.findAbove(target, 'div', 'differential-inline-comment')) { - return; - } - } catch (ex) { - // Continue if we're not inside an inline comment. + if (!canLinkNode(target)) { + return; } // If only part of the symbol was edited, the symbol name itself will diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-drag-and-drop-textarea.js 2022-06-14 16:29:55.000000000 +0000 @@ -2,6 +2,7 @@ * @provides javelin-behavior-aphront-drag-and-drop-textarea * @requires javelin-behavior * javelin-dom + * javelin-json * phabricator-drag-and-drop-file-upload * phabricator-textareautils */ @@ -10,6 +11,27 @@ var target = JX.$(config.target); + var metadata_node = JX.$(config.remarkupMetadataID); + var metadata_value = config.remarkupMetadataValue; + + function set_metadata(key, value) { + metadata_value[key] = value; + write_metadata(); + } + + function get_metadata(key, default_value) { + if (metadata_value.hasOwnProperty(key)) { + return metadata_value[key]; + } + return default_value; + } + + function write_metadata() { + metadata_node.value = JX.JSON.stringify(metadata_value); + } + + write_metadata(); + if (JX.PhabricatorDragAndDropFileUpload.isSupported()) { var drop = new JX.PhabricatorDragAndDropFileUpload(target) .setURI(config.uri) @@ -25,6 +47,10 @@ drop.listen('didUpload', function(file) { JX.TextAreaUtils.insertFileReference(target, file); + + var phids = get_metadata('attachedFilePHIDs', []); + phids.push(file.getPHID()); + set_metadata('attachedFilePHIDs', phids); }); drop.start(); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-fancy-datepicker.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-fancy-datepicker.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-fancy-datepicker.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-fancy-datepicker.js 2022-06-14 16:29:55.000000000 +0000 @@ -424,6 +424,13 @@ value_m += 12; value_y--; } + // This relies on months greater than 11 rolling over into the next + // year and days less than 1 rolling back into the previous month. + var last_date = new Date(value_y, value_m, 0); + if (value_d > last_date.getDate()) { + // The date falls outside the new month, so stuff it back in. + value_d = last_date.getDate(); + } break; case 'd': // User clicked a day. diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-hovercard.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-hovercard.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-hovercard.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-hovercard.js 2022-06-14 16:29:55.000000000 +0000 @@ -5,10 +5,18 @@ * javelin-stratcom * javelin-vector * phui-hovercard + * phui-hovercard-list * @javelin */ -JX.behavior('phui-hovercards', function() { +JX.behavior('phui-hovercards', function(config, statics) { + if (statics.hovercardList) { + return; + } + + var cards = new JX.HovercardList(); + statics.hovercardList = cards; + // We listen for mousemove instead of mouseover to handle the case when user // scrolls with keyboard. We don't want to display hovercard if node gets @@ -23,65 +31,19 @@ return; } - var data = e.getNodeData('hovercard'); + var node = e.getNode('hovercard'); + var data = e.getNodeData('hovercard').hovercardSpec; + + var card = cards.getCard(data); - JX.Hovercard.show( - e.getNode('hovercard'), - data.hoverPHID); + cards.drawCard(card, node); }); JX.Stratcom.listen( 'mousemove', null, function (e) { - if (!JX.Hovercard.getCard()) { - return; - } - - var root = JX.Hovercard.getAnchor(); - var node = JX.Hovercard.getCard(); - var align = JX.Hovercard.getAlignment(); - - var mouse = JX.$V(e); - var node_pos = JX.$V(node); - var node_dim = JX.Vector.getDim(node); - var root_pos = JX.$V(root); - var root_dim = JX.Vector.getDim(root); - - var margin = 20; - - if (align == 'south') { - // Cursor is below the node. - if (mouse.y > node_pos.y + node_dim.y + margin) { - JX.Hovercard.hide(); - } - - // Cursor is above the root. - if (mouse.y < root_pos.y - margin) { - JX.Hovercard.hide(); - } - } else { - // Cursor is above the node. - if (mouse.y < node_pos.y - margin) { - JX.Hovercard.hide(); - } - - // Cursor is below the root. - if (mouse.y > root_pos.y + root_dim.y + margin) { - JX.Hovercard.hide(); - } - } - - // Cursor is too far to the left. - if (mouse.x < Math.min(root_pos.x, node_pos.x) - margin) { - JX.Hovercard.hide(); - } - - // Cursor is too far to the right. - if (mouse.x > - Math.max(root_pos.x + root_dim.x, node_pos.x + node_dim.x) + margin) { - JX.Hovercard.hide(); - } + cards.onMouseMove(e); }); // When we leave the page, hide any visible hovercards. If we don't do this, @@ -91,7 +53,7 @@ ['unload', 'onresize'], null, function() { - JX.Hovercard.hide(); + cards.hideCard(); }); }); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-lightbox-attachments.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-lightbox-attachments.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/behavior-lightbox-attachments.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/behavior-lightbox-attachments.js 2022-06-14 16:29:55.000000000 +0000 @@ -94,16 +94,12 @@ if (target_data.viewable) { img_uri = target_data.uri; - var alt_name = ''; - if (typeof target_data.name != 'undefined') { - alt_name = target_data.name; - } img = JX.$N('img', { className : 'loading', - alt : alt_name + alt : target_data.alt || null } ); } else { diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/Hovercard.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/Hovercard.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/Hovercard.js 2020-09-25 09:12:06.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/Hovercard.js 2022-06-14 16:29:55.000000000 +0000 @@ -10,163 +10,19 @@ JX.install('Hovercard', { - statics : { - _node : null, - _activeRoot : null, - _visiblePHID : null, - _alignment: null, - - fetchUrl : '/search/hovercard/', - - /** - * Hovercard storage. {"PHID-XXXX-YYYY":"<...>", ...} - */ - _cards : {}, - - getAnchor : function() { - return this._activeRoot; - }, - - getCard : function() { - var self = JX.Hovercard; - return self._node; - }, - - getAlignment: function() { - var self = JX.Hovercard; - return self._alignment; - }, - - show : function(root, phid) { - var self = JX.Hovercard; - - if (root === this._activeRoot) { - return; - } - - self.hide(); - - self._visiblePHID = phid; - self._activeRoot = root; - - if (!(phid in self._cards)) { - self._load([phid]); - } else { - self._drawCard(phid); - } - }, - - _drawCard : function(phid) { - var self = JX.Hovercard; - // card is loading... - if (self._cards[phid] === true) { - return; - } - // Not the current requested card - if (phid != self._visiblePHID) { - return; - } - // Not loaded - if (!(phid in self._cards)) { - return; - } - - var root = self._activeRoot; - var node = JX.$N('div', - { className: 'jx-hovercard-container' }, - JX.$H(self._cards[phid])); - - self._node = node; - - // Append the card to the document, but offscreen, so we can measure it. - node.style.left = '-10000px'; - document.body.appendChild(node); - - // Retrieve size from child (wrapper), since node gives wrong dimensions? - var child = node.firstChild; - var p = JX.$V(root); - var d = JX.Vector.getDim(root); - var n = JX.Vector.getDim(child); - var v = JX.Vector.getViewport(); - var s = JX.Vector.getScroll(); - - // Move the tip so it's nicely aligned. - var margin = 20; - - - // Try to align the card directly above the link, with left borders - // touching. - var x = p.x; - - // If this would push us off the right side of the viewport, push things - // back to the left. - if ((x + n.x + margin) > (s.x + v.x)) { - x = (s.x + v.x) - n.x - margin; - } - - // Try to put the card above the link. - var y = p.y - n.y - margin; - self._alignment = 'north'; - - // If the card is near the top of the window, show it beneath the - // link we're hovering over instead. - if ((y - margin) < s.y) { - y = p.y + d.y + margin; - self._alignment = 'south'; - } - - node.style.left = x + 'px'; - node.style.top = y + 'px'; - }, - - hide : function() { - var self = JX.Hovercard; - self._visiblePHID = null; - self._activeRoot = null; - if (self._node) { - JX.DOM.remove(self._node); - self._node = null; - } - }, - - /** - * Pass it an array of phids to load them into storage - * - * @param list phids - */ - _load : function(phids) { - var self = JX.Hovercard; - var uri = JX.$U(self.fetchUrl); - - var send = false; - for (var ii = 0; ii < phids.length; ii++) { - var phid = phids[ii]; - if (phid in self._cards) { - continue; - } - self._cards[phid] = true; // means "loading" - uri.setQueryParam('phids['+ii+']', phids[ii]); - send = true; - } - - if (!send) { - // already loaded / loading everything! - return; - } - - new JX.Request(uri, function(r) { - for (var phid in r.cards) { - self._cards[phid] = r.cards[phid]; - - // Don't draw if the user is faster than the browser - // Only draw if the user is still requesting the original card - if (self.getCard() && phid != self._visiblePHID) { - continue; - } - - self._drawCard(phid); - } - }).send(); + properties: { + hovercardKey: null, + objectPHID: null, + contextPHID: null, + isLoading: false, + isLoaded: false, + content: null + }, + + members: { + newContentNode: function() { + return JX.$H(this.getContent()); } } + }); diff -Nru phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/HovercardList.js phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/HovercardList.js --- phabricator-0~git20200925/phabricator/webroot/rsrc/js/core/HovercardList.js 1970-01-01 00:00:00.000000000 +0000 +++ phabricator-0~git20220903/phabricator/webroot/rsrc/js/core/HovercardList.js 2022-06-14 16:29:55.000000000 +0000 @@ -0,0 +1,233 @@ +/** + * @requires javelin-install + * javelin-dom + * javelin-vector + * javelin-request + * javelin-uri + * phui-hovercard + * @provides phui-hovercard-list + * @javelin + */ + +JX.install('HovercardList', { + + construct: function() { + this._cards = {}; + this._drawRequest = {}; + }, + + members: { + _cardNode: null, + _rootNode: null, + _cards: null, + _drawRequest: null, + _visibleCard: null, + + _fetchURI : '/search/hovercard/', + + getCard: function(spec) { + var hovercard_key = this._newHovercardKey(spec); + + if (!(hovercard_key in this._cards)) { + var card = new JX.Hovercard() + .setHovercardKey(hovercard_key) + .setObjectPHID(spec.objectPHID) + .setContextPHID(spec.contextPHID || null); + + this._cards[hovercard_key] = card; + } + + return this._cards[hovercard_key]; + }, + + drawCard: function(card, node) { + this._drawRequest = { + card: card, + node: node + }; + + if (card.getIsLoaded()) { + return this._paintCard(card); + } + + if (card.getIsLoading()) { + return; + } + + var hovercard_key = card.getHovercardKey(); + + var request = {}; + request[hovercard_key] = this._newCardRequest(card); + request = JX.JSON.stringify(request); + + var uri = JX.$U(this._fetchURI) + .setQueryParam('cards', request); + + var onresponse = JX.bind(this, function(r) { + var card = this._cards[hovercard_key]; + + this._fillCard(card, r.cards[hovercard_key]); + this._paintCard(card); + }); + + card.setIsLoading(true); + + new JX.Request(uri, onresponse) + .send(); + }, + + _newHovercardKey: function(spec) { + var parts = [ + spec.objectPHID, + spec.contextPHID + ]; + + return parts.join('/'); + }, + + _newCardRequest: function(card) { + return { + objectPHID: card.getObjectPHID(), + contextPHID: card.getContextPHID() + }; + }, + + _getCardNode: function() { + if (!this._cardNode) { + var attributes = { + className: 'jx-hovercard-container' + }; + + this._cardNode = JX.$N('div', attributes); + } + + return this._cardNode; + }, + + _fillCard: function(card, response) { + card.setContent(response); + card.setIsLoaded(true); + }, + + _paintCard: function(card) { + var request = this._drawRequest; + + if (request.card !== card) { + // This paint request is no longer the most recent paint request. + return; + } + + this.hideCard(); + + this._rootNode = request.node; + var root = this._rootNode; + var node = this._getCardNode(); + + JX.DOM.setContent(node, card.newContentNode()); + + // Append the card to the document, but offscreen, so we can measure it. + node.style.left = '-10000px'; + document.body.appendChild(node); + + // Retrieve size from child (wrapper), since node gives wrong dimensions? + var child = node.firstChild; + + var p = JX.$V(root); + var d = JX.Vector.getDim(root); + var n = JX.Vector.getDim(child); + var v = JX.Vector.getViewport(); + var s = JX.Vector.getScroll(); + + // Move the tip so it's nicely aligned. + var margin = 20; + + // Try to align the card directly above the link, with left borders + // touching. + var x = p.x; + + // If this would push us off the right side of the viewport, push things + // back to the left. + if ((x + n.x + margin) > (s.x + v.x)) { + x = (s.x + v.x) - n.x - margin; + } + + // Try to put the card above the link. + var y = p.y - n.y - margin; + + var alignment = 'north'; + + // If the card is near the top of the window, show it beneath the + // link we're hovering over instead. + if ((y - margin) < s.y) { + y = p.y + d.y + margin; + alignment = 'south'; + } + + this._alignment = alignment; + node.style.left = x + 'px'; + node.style.top = y + 'px'; + + this._visibleCard = card; + }, + + hideCard: function() { + var node = this._getCardNode(); + JX.DOM.remove(node); + + this._rootNode = null; + this._alignment = null; + this._visibleCard = null; + }, + + onMouseMove: function(e) { + if (!this._visibleCard) { + return; + } + + var root = this._rootNode; + var node = this._getCardNode(); + var alignment = this._alignment; + + var mouse = JX.$V(e); + var node_pos = JX.$V(node); + var node_dim = JX.Vector.getDim(node); + var root_pos = JX.$V(root); + var root_dim = JX.Vector.getDim(root); + + var margin = 20; + + if (alignment === 'south') { + // Cursor is below the node. + if (mouse.y > node_pos.y + node_dim.y + margin) { + this.hideCard(); + } + + // Cursor is above the root. + if (mouse.y < root_pos.y - margin) { + this.hideCard(); + } + } else { + // Cursor is above the node. + if (mouse.y < node_pos.y - margin) { + this.hideCard(); + } + + // Cursor is below the root. + if (mouse.y > root_pos.y + root_dim.y + margin) { + this.hideCard(); + } + } + + // Cursor is too far to the left. + if (mouse.x < Math.min(root_pos.x, node_pos.x) - margin) { + this.hideCard(); + } + + // Cursor is too far to the right. + if (mouse.x > + Math.max(root_pos.x + root_dim.x, node_pos.x + node_dim.x) + margin) { + this.hideCard(); + } + } + } +});