diff --git a/.ci/scripts/esp_idf_mirror.py b/.ci/scripts/esp_idf_mirror.py index 75a9e036f95..cef0791381e 100644 --- a/.ci/scripts/esp_idf_mirror.py +++ b/.ci/scripts/esp_idf_mirror.py @@ -68,7 +68,7 @@ def main() -> None: { "spec": requirement.version_spec, "source": requirement.source.type, - "registry_url": None, + "registry_url": requirement.registry_url, "is_public": requirement.is_public, "require": requirement.is_required, "name": None if is_idf else name, diff --git a/.ci/scripts/espressif_idf_upload_requirements.txt b/.ci/scripts/espressif_idf_upload_requirements.txt new file mode 100644 index 00000000000..5ce9301582f --- /dev/null +++ b/.ci/scripts/espressif_idf_upload_requirements.txt @@ -0,0 +1,460 @@ +# Hash-locked requirements of upload_espressif_idf_component.sh, whose jobs can +# publish to the ESP Component Registry. Regenerate with pip-tools under Python +# 3.11, the upload jobs' Python, from the single line idf-component-manager==X.Y.Z: +# pip-compile --allow-unsafe --generate-hashes --no-emit-index-url --strip-extras +annotated-types==0.8.0 \ + --hash=sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7 \ + --hash=sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0 + # via pydantic +certifi==2026.10.23 \ + --hash=sha256:a9895e6e2758b371e0545e321a3a8fd1fcfd9829ada8824a936dfb16aaaf36cd \ + --hash=sha256:e9b54de76e530bb6cf0ccd036787103acb58fd42ba930ea8bf948ddbaa2f61d1 + # via requests +charset-normalizer==3.5.2 \ + --hash=sha256:01077390b03f7988f11d700a2194e69b119741a86b1a638b1db88891e3eced8e \ + --hash=sha256:01b0c0d2262a9e28e8484a278c7e1b5d650e3ac8cf2683d2967e25899f208bdf \ + --hash=sha256:04851f73ae72b8413dddadb16a49dfee95263553741fd42d546f7d66907e6be5 \ + --hash=sha256:0521c5665880b33d603717defa76c094048900010897909952397feb3039da56 \ + --hash=sha256:0774bf9bf620249fee3e0b8b9fd3065de213be30f3aa94ce2494b3b638949e26 \ + --hash=sha256:0891b9d3903c5571c03771ca669a4b0ec5618ca722a5c957d3d29cd4e5062848 \ + --hash=sha256:0c951d5e6dd9c2ff60609476752bee49da4206adde960ebc247766937f72e718 \ + --hash=sha256:0fed1d06615f022ee3b13caf5e8b180cfea32bb2c5aded8a9d44277afc040f93 \ + --hash=sha256:114e4d0c92d618409ed82a99e22b5c5e768fe995f2973f78265f4524f49d4640 \ + --hash=sha256:11912e4bb14baae7c5d8791aa55ba0a3a03ec6729073307b0f57270abaa713d3 \ + --hash=sha256:11a4d68a6ecda3292cb1e50239e111543ba5d709bb62a6b4ea1afcfa729d8875 \ + --hash=sha256:124fbf1a8ff966d87ae05bb8bd45a71f966055ed8bba320d0c7cf450bc5f4d0e \ + --hash=sha256:1461ac396c4fdb983a675f20aa555624f0ee18ac83d832b9244ffff3d8055275 \ + --hash=sha256:1503bccbeb36d5527790c3930327704c39af22de3112f1b1666a9f3ce15ee204 \ + --hash=sha256:15bb4005af6320d259dc7593ca84a38d7fe06a421dbcf7b910ae23979101e787 \ + --hash=sha256:15c44f7edfd477b06f517a5cc317fc1707edb9de2c865f43d4b6513907473234 \ + --hash=sha256:16fa0eccf81304b79c5cd87f9271c3b85dd9dd99245e4422ae9c0dd45e0f99d3 \ + --hash=sha256:183b88127acdb4fabe59d951ab424faf1af7b63cdbb5f776186c1ea2ffcaed98 \ + --hash=sha256:195c26fb65950f8fce54e26349852b7bdd7c5f120aeefbcc440b8a20faaed4a3 \ + --hash=sha256:1afb975bd5d68d5ce9f6b6d44fdf2f7e34b895a35e95708a7a91b20a3b51d187 \ + --hash=sha256:1b4cbc7c3491ccb4aa17fcd8165649d01cf39f76de1696da8631b5f71b85401d \ + --hash=sha256:1bc0baf5ef96b6ede57d47f4b8fe4d9d84019c3bfcbeb20a41edc6a6ee341f1f \ + --hash=sha256:1c50fe28bbc2ced33386f298650d91218076c05420e6cbd790b913adc41659e7 \ + --hash=sha256:1db38f4c5496827c1a501846d64d14c3b80c7e6714e406cd7dc36a9899fa1011 \ + --hash=sha256:211d5a3eb6af8f513b8d4ca19a8c1b7accab1b5f0d3175f9826b03c1a920dc1f \ + --hash=sha256:23851fb4e1b85ed3f6c2a27b777cdfe2e19fb5b38429a8faf38c7542b7665869 \ + --hash=sha256:254eb48b9fa5ee9898a3c445825a1f340fe53712a098904b39b0bddba8ea3cb1 \ + --hash=sha256:2625388c6c754520c37abaf3b41eb34d1cc4a373f457898f08606c8e362b891d \ + --hash=sha256:281cb91036248400f4cc957495cccd44c275c2e0c5854f7e45ac5cf7dc193847 \ + --hash=sha256:28a15fdad492a99b6eccfaaed66ef3f74050680545ea61ec8b2f4c538f1f1320 \ + --hash=sha256:28b4f0d66fb834ff90f28209ac7bce77868c45d8c93e26f906709d9b7c2e1af9 \ + --hash=sha256:2a925889534b3748302dae5dead07cc13480de1dac3aea80a941b729b471ef93 \ + --hash=sha256:2b7b3bbfb4fe8ef40600792d762fbaa9057559f9d3fad209525b7a22b99e91fd \ + --hash=sha256:2c9ad19a6cfcd5ea5c0d41161d22f9df1dcc277e9bef2751391334546a314c00 \ + --hash=sha256:2cc961b171b3f3440f410489ab3573e86aea8736134ebbb40ea1338b7f0831bc \ + --hash=sha256:2ce45c6627b22c47e390bc91a41c3d13032192e699fa0bea96e9671b373d69b0 \ + --hash=sha256:2e06a3a98f916dd41d27f3105e02e7a40181c98c94b9158733d03a6f80506c09 \ + --hash=sha256:304d5463e65a35d7bb0850550e0780395395f6fcf452f04db7d5ca7cecc425ac \ + --hash=sha256:304d8e4d493af723536393eee0c689eb7813f4a474c8b479dee63f1fdd98f621 \ + --hash=sha256:30fcd120b732aa79317f08dee04d7de0847822e4cf7ee0e9f445bb958832252c \ + --hash=sha256:31f3930700408d211f13378ccbe1c40845d8da54bd0681fac3a9b5aae81c7aa8 \ + --hash=sha256:34276fd796040bf0993ab33a369aa572e6979c7aab225a88893667ad8eac8f7a \ + --hash=sha256:355ad8011081dec5412240c087a9a0c9d4d5039f3ed11a3f13e18c2b29b56c51 \ + --hash=sha256:38a873987f3be698494da8b2e3085e29da02da7b633dce73e79c699a113d7bf0 \ + --hash=sha256:39de2a259fc954455c57274dc94c79d5842774e1247a016aff30bc0efed0f4ef \ + --hash=sha256:3d14b50de6bf4d0edf857a9386836846f982b8f524e188e2e68b96d702bcf4aa \ + --hash=sha256:3d21b8b13c7592db2ac5e544a6d83187b995257472b0c9e8351b6d507ae37ed6 \ + --hash=sha256:3d31298449090ab8d47b7b1b2a555ff73cac7ed438a08b7ac160980c7ebed649 \ + --hash=sha256:3ddacd27458c45bdacd6bd6db644bfb730efbf9e830310186e3045c9c5be8fb2 \ + --hash=sha256:3df041de8887954562c9b261cba85ca0e9ded74048daf125f45edcfaa4832229 \ + --hash=sha256:40ab6bffa02ae10a0581e6c198be7d2d8ca5c2a0c64e4ed3465d766df457573e \ + --hash=sha256:4275811936e2f06feff5e598fb42a1b7ae852da8e39605211892b56b81a34efd \ + --hash=sha256:443eae2bf318abeaf6f15d785138f71fd6de770e99a92158b8b814265e079115 \ + --hash=sha256:447441e76ec720b15e64418d32e092297340387053047c7c694f579efb0ee1d9 \ + --hash=sha256:4495c5002a7b28557e7e222e77e0b661183e432b7d6d2e788101e3f240e05b8c \ + --hash=sha256:44bd4fbb29dfbeba60e7d2bd000c59e4b21ddb3cc53912b14048d37092706d7c \ + --hash=sha256:4685902cf26edf013ed7a3da0f426ebba7a00ebb9541386d835afbf002c11cab \ + --hash=sha256:498dc3188ca05a68231ac3fdbfc7f57eb67e1343c30e0fea17f8218c1599b253 \ + --hash=sha256:4c2b5031f63e331e3839b40aed2dd6f191e9c07edbde303e7876846ea1946995 \ + --hash=sha256:4d48f2d08b9de5864e2c8744d4461b862fb149a18274abc8b698c45975573438 \ + --hash=sha256:4f87960d57feabfb618e4e0af6e7371645fa26a277860739d6e5d6e0012c92f0 \ + --hash=sha256:50e3adfb96fc189eb27b1cf62d3b598b89b4bb0420d93a3d3e42e137409011be \ + --hash=sha256:51cf45226a9b588d0d2b4880c62d686934b63ab0bd79ca23ab0e9762eb27441b \ + --hash=sha256:52aa6992700996af31f375de0c6bacd402b0097fe40b53c426b9f51a90ebabc7 \ + --hash=sha256:55ea99acb17b9325618de155a0cd6a2e8f5d10be008113e1d433bbb58db543b2 \ + --hash=sha256:56bc200a365efb37383b7852e4cc5898d3b2da5987289b543956cf8cad71018a \ + --hash=sha256:588461c2e8384d309bd63e5826019b6977bc66d629b99ac8737bb795d7b2cb5a \ + --hash=sha256:58ca3755ee7ff7f59b57789ec9833c9de9ea275405cdd240eda1f193112e398a \ + --hash=sha256:58f361dcbab699cf8f42db3f47c8e7fd1036f138c23a5d08de9fde5f425a730c \ + --hash=sha256:598a11a2c7ebaa5334bf698bf29568c9c390abac6a154d8170fedecd1cea38c5 \ + --hash=sha256:59f63901b0031c3136cf64704dcb21de0bbae62ce2c9529bc39d27665463de37 \ + --hash=sha256:5cde776b7cc66e4f6c99612cea4aa7269aa65863f7a15841b2c264f103822f4e \ + --hash=sha256:5e2b6b57e9733d39f0c9fd3185efa6b8e29652c4cd8fe94180272cf6ed9a78c4 \ + --hash=sha256:5fb29fb8cd1a46c27a1bf9613ad5ec2599310d46b4025d9556404a6b6a292800 \ + --hash=sha256:6045373d5a89a5ec71afde535db987ca28e76dfa276c2d4c818265b375d4b055 \ + --hash=sha256:619799369eeef6366ed3e8755a5670f4f2f0fb6b30a0fd7264dc0fdc2357058e \ + --hash=sha256:62588a277bfb59def052abd940703fa35107152bf479781a878617d60faf8fb5 \ + --hash=sha256:62603db9a7caa0802eaa28c1c46fecd7b3a263a774069c24c3c28c302448721c \ + --hash=sha256:65cd72beeeca9d3aaea1201e5923859f308f952f9c71de93f06063c79f0f7a3b \ + --hash=sha256:68eb192d85ab8e5f6ec69c2bc6ac0179fbf04a5ac1569d12fbef74883fe102d0 \ + --hash=sha256:6bd128f206a7752ae1f2ab6c61bf8a24ba28913a10df8b14c2637b973ff97a80 \ + --hash=sha256:6be488a102b8cf28d0391d8c4ba7748938ae28b78ad901f8585520fca33ead1a \ + --hash=sha256:7218e8f32b0956cfcd048fd42d9d5779809745ca1d86113ca56f66e7ae1549c4 \ + --hash=sha256:7441d755b7ab94f8d4eb3e43ec05482d760842fd263d003a99102d742cd835e2 \ + --hash=sha256:749e97e1b32313717a565abbe321bc2190bc8b35f1a67e4cdbc7c56c8d8ffe58 \ + --hash=sha256:75a3ceed0724d625d64b86ca20aba182e4df462e04c2414fc941c0f523f06aac \ + --hash=sha256:780fbe7cab297b81dad9fb8dc5eb003c0468ffb0d9e5f65068c53a34661a96bc \ + --hash=sha256:78456a747de8dc58360ffa581f30a002baf5aa28cb262536545e91f113ed7639 \ + --hash=sha256:7967d08cf06dee78443b874f98c98036f624f3a4e73e11f9f64f5be4d25393cf \ + --hash=sha256:7a881931aa470808df94a8c380eed2bbbc76cd9dc622310f99665658c821eb6d \ + --hash=sha256:7dcd882da75ef9adf94903b1e3b9419e8aa8fb4c7396822b834b9ef7fb96954f \ + --hash=sha256:7e841fb9010836c992c9f12fcbd43a831de93a5f726fc1ccd8ca1d0268c5014c \ + --hash=sha256:7fdde2c9fd9e3eca40631e024664cf2584272cc8f96308cbe5fdfc930f51d8bc \ + --hash=sha256:8024d00c3faf3fc0c16e07a69f4405e8eac7cc0ab15f65fe6cf43827c4cf72b4 \ + --hash=sha256:80d02b6f04e92601a081dd97b23d3128033098bff5d35d392ddcc0476ea11253 \ + --hash=sha256:838dcc90063569a0448120554591a1d6c4a4ffe11babf048908793154ab86ade \ + --hash=sha256:849df64e889b2e17230d58410a03dba311a65b163508fd33679b2b737d4b7858 \ + --hash=sha256:87475fabc8d9996fd9c27debb395e642e8c838d78a00b6e932227a0e06b81e26 \ + --hash=sha256:87e50a3e7cb90af586b6c5faf23e302a970415ac73bd7bd90a515a04b427ef96 \ + --hash=sha256:89b53f3cda69831909888e0494f4fa0bcd3537e3e138dabeb620bd6ad946bae8 \ + --hash=sha256:8a893cc101149f80a653f82062ebc95b34525a2614382e1da5458fe7c6997249 \ + --hash=sha256:8b2bfab86aa71ae13aa41a6a26aab338e0db2b8bc75434b05aea89e011ff35a4 \ + --hash=sha256:8d86d6fc60743dc916eb79e2eb1ec4818e21e427731543af40a3021851174a13 \ + --hash=sha256:915563965d418f986e7e145accc592eae9e1a1be3566ff98a05d7a9ec42a76e1 \ + --hash=sha256:92888bb3187c5ba50500b00b3b310c9f2c651709d28036077680cb5255450a03 \ + --hash=sha256:93223adc95033dd47133a46ccfc316a0139176fd79085762e27202ec56018f03 \ + --hash=sha256:9373ad13ef0d2c0fb761e04e55bfdee5a08b52cef2c882c8fbe9935b1517152e \ + --hash=sha256:9409a8bf35cf78353942504b24a57de3d75b708997a1e4bd8db71ac8633ce364 \ + --hash=sha256:9b7f416ff0978e2f2249330527f0ad6fa02f4932e6199692d3b52da2048c19e4 \ + --hash=sha256:9bde855991b7e362c146535e3136a50bfaffc0487d38b33ca7e5edefc6e23849 \ + --hash=sha256:9cae88599c7219005d879f98e5ed53341e9a122af585e1091200358a3003d2a0 \ + --hash=sha256:9cf9b1a857e25c4baceeb3624e92a56df3668f398c4acba74e174d81fb4d1d3a \ + --hash=sha256:9f56f72050826f63dcee7a7f55b0a77168cb3bfc553fd405e7f8f9ece75a4036 \ + --hash=sha256:a090bb2c68df85450502e3e20d665e3a5af9c65a84d6508ed477badd49166fd3 \ + --hash=sha256:a192e2c40070d92c3ccf777e3a5c4ff515573cd2bb7ed0c537fdadbbec5bbf21 \ + --hash=sha256:a19a731138fc27d5682277d3b9df22855cea1239bce7fcec5f78f42ef2d1f3c3 \ + --hash=sha256:a66c3bc5ab1f0ff2164fc9965ddd611ff0802173f4b9d24554c563f6ab7e1d6e \ + --hash=sha256:a815775b6c38d4e0ff7bcffbeba67feded90202bb6a226b8dd35f1c855217413 \ + --hash=sha256:a89012d6d5476ee112d20d998570ed58df2260a852afb1758809cd6900411d21 \ + --hash=sha256:ae4f5fea5b8b8ccff88238cc8569303e5ee95efae67fa62922a311397a71f346 \ + --hash=sha256:b6856554c4f44d79fc2307d5768854310a8f0096e501c75637542c82292b0429 \ + --hash=sha256:b6b751274acb69d77b3323d6b7dbaa3c7fdfc1eb829b7eb61d262f32e1af9685 \ + --hash=sha256:b736353c0a625bbd5fcec108576e2385db3496f4f771f785ff32e108d3c3bc45 \ + --hash=sha256:b7fd005a73d9e657273b7a10dc71a9e03c8fb9ee6999798d6918ce095b81ac7f \ + --hash=sha256:b91363207bd9dc966a691e959bb47f64b30f7ac4b072be9968b366982f7db77c \ + --hash=sha256:ba0b1d2620edf869789c3879223f52bf2afc5d31b3cb47cc57b3a12c05e2aa9d \ + --hash=sha256:bbbfc8e28816f19d7c0f1816664980c0a9875d01b27cdf8eedddb639d9e108ad \ + --hash=sha256:bd16aabe4a02a297c23417aa17ac6299dbd8c49f673bcd645b4929b11f5a4400 \ + --hash=sha256:c0afc6800ba57ccc350374c5bd6150419915d95ce93cdbab2d783d75eaf30ecb \ + --hash=sha256:c6708715abcf3c73b99508253e961a9967f02fe536532834149574eda6de0d1c \ + --hash=sha256:c7c9ab723cde841fefb34efbad91e87f00a674b1fe1cd0784fde742bf2c154dc \ + --hash=sha256:c8f3d67aeaf55f017982b73683f0e7342ba2f6635a78f69ce89ebb26aa411e5c \ + --hash=sha256:c9790464842f85f437dbbb54417eda1e0e6bfc52dd8d22d6fd1c994b73b2dc74 \ + --hash=sha256:ca403d7e4798f525fdfc78e258820419cbbd0f0ecbab9de7840e3c017cf6b8cf \ + --hash=sha256:d008d90a7f2471519aef0c90dfbe73b3e6e4d5e66ac48e19154c17e89e98b604 \ + --hash=sha256:d19fbd981a488e22cd04883659ca6b08f50b5974f9fd7c95655ef6a043e5893f \ + --hash=sha256:d1befeed746d247c81127bb14de9dc3d30edb6e5976d34f83f86ed262b1d9105 \ + --hash=sha256:d2374b62878abb00cd8309b32af6c0b715cd02dec0ca74ef12e5069bdc64144a \ + --hash=sha256:d376bbd28b3a8999db1a103b3b388aee6f1ddeb3e51bc2172993efdcd86e064d \ + --hash=sha256:d4a7319f304a774bed22115bc891618e45f85065ab44ea6acd07d274e750519a \ + --hash=sha256:d6734d2ef8a50fbf8445c139477da401f50d62a0606bf00e20ec6d87773fefb1 \ + --hash=sha256:d760fe2a4d7c3b226cb9026d6a842868d52a7901bd98420e1baf14e80da85cf5 \ + --hash=sha256:d913de495d90407cd859d263bee2e5d1a4ed3eb6573c04e70d9ec619a7cbed7f \ + --hash=sha256:db19d07e2e0129e974a0e65d0064fc222a446cd5122c2fd4184d2af9fc734a9e \ + --hash=sha256:dca9ab98072a5a54ebacebdc45f53e645336b320c667410b061be1ca588ae709 \ + --hash=sha256:ddc7dacc8ece3a182e7f15cb862d1fd616b46d076cb1ae9dd232b2c38b655874 \ + --hash=sha256:ddf19c062bea7a0cc80f519243d2c01dd091be0cf952a0750d4ad576709559f5 \ + --hash=sha256:def79fa35ef0cef8d2accec024f4fdc7ead3012ff02f5215c783f39f03ef8cfc \ + --hash=sha256:df29a0a7107f7011e77f4eebdddec4c7331e24d787a0b21a46d63bdf7445da95 \ + --hash=sha256:e09a3942ecbdee5cce73ea9d42da82b81b72ac1bf031ce069b93b5adf4eac8cd \ + --hash=sha256:e242bb1c5e76e97dfa9e7f209a71e93a01d7f19ffdd5cfbb2e2d55b4f08f8ab0 \ + --hash=sha256:e243bd13217235fc7290c621941c3f5cc8b66e4872495be821d7436ba2fb838d \ + --hash=sha256:e2af3aad578aa6bd1384bcf4750fc285e5a9de53f40b7d41e5a0bf748edeb2b3 \ + --hash=sha256:e4e81e09c1578b8df602e3db08b0b3ea0a6947ad612f52bf8dc5ea8d47691f0c \ + --hash=sha256:e54da4baf05720032d527874d40b65fa4d7e5c6c6a43d0c3adbeffcaf275a2b3 \ + --hash=sha256:e80e6c2f55656b4824d72065abb4ddd6a525c74bd78a0aab5d9fc2cf4fb5af50 \ + --hash=sha256:ed2a239c0ea213acc1908150a3037257083c7c083128f1a4cec2ec4b97dca491 \ + --hash=sha256:ed905975ab14056a2e5eb1c376cb2e1ebc5396baf84163939c518556fccde9f5 \ + --hash=sha256:ee21e28f0430bd6dc9086c6e525d5e818a44a5ad19720c8a0ef766792f3eb5e5 \ + --hash=sha256:ee43c17b173d46a3212baa6ead3ae258eeabdae48c263a01ccf0218c366dd655 \ + --hash=sha256:ef4fcbf3327382cd4c9f540babd61248208af7b93eec4de397b4d5f58a09e288 \ + --hash=sha256:eff0ac9dbe711a4aee69bf04a83896aa9b85f19641264053a9f6d48573abb7dd \ + --hash=sha256:f0aa869112ef88429ae17820d99c3dd9504c9e9c671d3c246f3d7442cb051084 \ + --hash=sha256:f3c96f633825733f735c5a9cf21d21a257d8e1edf0b1cee0a064b9c424ca0f7d \ + --hash=sha256:f5833ad231be5eb6553de524a70f48d71b2c8563101750531e0b80184e175cd4 \ + --hash=sha256:f5ec61164adcec446f8969a3358ec3f9b26bbda3b9213e5586d219afa8df2915 \ + --hash=sha256:f7d486c83842422badd511868fd8a9a20e9407ace71564b6af47ce7e60a336c1 \ + --hash=sha256:fb9e68df06293761f9fe66ade60a9bc6d0f5e42b8acf2939a9158af86ab0e5bd \ + --hash=sha256:fc14a032f813bf5fe624d991960ea83e9715adc27e4c1830a2361eb1d02ac341 \ + --hash=sha256:fcff63213e8e6e47770541a4607175404f47cbb3ebea7b6058cc82d524a0e424 \ + --hash=sha256:fd1fbe0f116b6e55da77aca2c6ddcddcfac2186cbf78bdebf40fc156efca389d \ + --hash=sha256:fe9753dfee015c570d73df76f899f18444d41388bffcde097deba51c4fadbb9f + # via requests +click==8.5.1 \ + --hash=sha256:8bb5376d2006950386f8c6427613334a2acadc5f559cb80e638d00b4df957e37 \ + --hash=sha256:9bbfada76703fd1d784b83eea012e3e8c6a001a876543ef104fa56aaaeb072b4 + # via rich-click +esp-pylib==1.2.1 \ + --hash=sha256:c0854cc57b86e2745e9f7ac820d5d5e8a9f2c2d93caf12623c419b8d08d852f6 \ + --hash=sha256:fb05017676200e38dc182013c994e62d9088d377081c88562e14a2f5aaae6456 + # via idf-component-manager +idf-component-manager==3.1.2 \ + --hash=sha256:424494493b47b61ea0f7666d3018a71deecb77f21186bc8b6761b0b6f98e8f90 \ + --hash=sha256:75ad9e4452d1bf42bea0a77d72af679714e2bb147627d926cee114122b6e33a0 + # via the line above +idna==3.20 \ + --hash=sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44 \ + --hash=sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c + # via requests +jsonref==1.1.0 \ + --hash=sha256:32fe8e1d85af0fdefbebce950af85590b22b60f9e95443176adbde4e1ecea552 \ + --hash=sha256:590dc7773df6c21cbf948b5dac07a72a251db28b0238ceecce0a2abfa8ec30a9 + # via idf-component-manager +markdown-it-py==4.2.0 \ + --hash=sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49 \ + --hash=sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a + # via rich +mdurl==0.1.2 \ + --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ + --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba + # via markdown-it-py +pathvalidate==3.3.1 \ + --hash=sha256:5263baab691f8e1af96092fa5137ee17df5bdfbd6cff1fcac4d6ef4bc2e1735f \ + --hash=sha256:b18c07212bfead624345bb8e1d6141cdcf15a39736994ea0b94035ad2b1ba177 + # via idf-component-manager +psutil==7.2.2 \ + --hash=sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372 \ + --hash=sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9 \ + --hash=sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841 \ + --hash=sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63 \ + --hash=sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979 \ + --hash=sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a \ + --hash=sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b \ + --hash=sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9 \ + --hash=sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee \ + --hash=sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312 \ + --hash=sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b \ + --hash=sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9 \ + --hash=sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e \ + --hash=sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc \ + --hash=sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1 \ + --hash=sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf \ + --hash=sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea \ + --hash=sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988 \ + --hash=sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486 \ + --hash=sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00 \ + --hash=sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8 + # via idf-component-manager +pydantic==2.14.3 \ + --hash=sha256:1054f237f4d4733e5a30e1e2333bd33a2004ab9ab1510bd053a9a31bb48e232d \ + --hash=sha256:3f7b347782ab7e4cf4c798496ae3a82787d9f21ec12676a9c564355eeef8daa8 + # via + # idf-component-manager + # pydantic-settings +pydantic-core==2.50.4 \ + --hash=sha256:0001d6920e3a5d92758cda460d6dc9f918a78ad6d5d092f1c8b5395e6b775356 \ + --hash=sha256:0574866e05f6adeecc520d87e87dd06210c0a51706341f6ef8421572f5a64444 \ + --hash=sha256:09450778e3ab58d3f565899fcfbf6c82926e31af29e28e799d1d50941316e0cb \ + --hash=sha256:0af56dbf8822ba9f4efcbbfdc15478f8b6fb08f1609860cb50aa2cc8476b3c34 \ + --hash=sha256:0b059a7968b1911be5a2d9a8234827ab0bef9d1e465d4b42da525894143550e8 \ + --hash=sha256:0ec20aca2b067369913716847f7dfe5f4dddf16a46965b7a70bbad5defaaba86 \ + --hash=sha256:0f87ae9db5ba8d8de40dcb93982cf8dd544e6552a80d3345af51941cc2146b80 \ + --hash=sha256:1239daaf063e62213ca1f34d96663900bd7510c42a786e843fd328af70e46445 \ + --hash=sha256:13b6dd62b5279f5b9d72f3bf918a35443ee8bd549241d9dc52d79a2c3b6d7016 \ + --hash=sha256:15bece43a02ad543c621c8305e67dedb5f27d378c5ba741e5a2c36523f8ef37f \ + --hash=sha256:16902a147b3da4840612164a5e67947104d63e978f7a57c395877a5e26690b9c \ + --hash=sha256:1afefe44ec042fbabfb4483ea258c04cf75ff4ff328d754f09b321fdaa232aca \ + --hash=sha256:1de7be9a66fc8536770481ab64a05aae5067c725f2b29a09543af00e6a417b97 \ + --hash=sha256:1e20cbde2b6deb33a51d08cd168454dd9044ec7d4474056f4d98d63f51578783 \ + --hash=sha256:2039e323acee9abfec1fb5f661776e8965fe5928f3b7f8431900a774cba5c317 \ + --hash=sha256:219114f8dcdcbe4720d82ef016b1287ce5a0a67d7c69ca61524eb72e82aac344 \ + --hash=sha256:22e874666bdbd96d6bf629d32cd8ab376fedf1fd62585b52a42b9fa9fa6c20b6 \ + --hash=sha256:23a9ba564b2db709ff16eca990992ba95a19069972b34bff87c81d4b473cd755 \ + --hash=sha256:25e7e1080f9f7ce7cd9d114b31470ce912771bd02f38c824721d3c35d312abff \ + --hash=sha256:26cb012c4b8ca9f847bd0ac15978bd3d0f55b050bfbe6c47355edfc7e945029b \ + --hash=sha256:29358a8ca74e7d81158d14e2b10c904bd18773293ae3788716c0626fe0342347 \ + --hash=sha256:2980a701be88f9128a7470189fa3bcda5387f76c298a6f8e000fc29eb2a6f4e7 \ + --hash=sha256:2a60ec2a57ac3ef3767e526e9bf706ec75aa3d79c4ea134d9d4fcf7c62a297a7 \ + --hash=sha256:2f42584e5785385f681163a42506cab0d51295e17599a648396c52a7046c1372 \ + --hash=sha256:2f5cc5bcb94063fbbdfd285a2b302da34af07491337c10bb35de1d5220fa1583 \ + --hash=sha256:2f6767122b37c780bb756a720a4eef2bc6a050a0a1143428834b3cbc89448bd2 \ + --hash=sha256:300753f71c73302e218124baf995f00058e085cd01869bd9610bcbd0bd4500c1 \ + --hash=sha256:30d4dc35bc0eea52202a90b3820445ee0072c820241bfa710a623a078c9b267b \ + --hash=sha256:32a991aebd165f227b7c7c60bb9d66c2c7de9c24308552da264c9938fde0f8d6 \ + --hash=sha256:32d6dda86383645ec428ea64dfc277036f5cbc60a72238eab28b91a3fdb9a113 \ + --hash=sha256:33b21f69540a12c2053cd1d95766d8bd9667a3897f7c712a642de8aa37eb0865 \ + --hash=sha256:39f489ce31272073e6e146f6781690f9c1ee8c126836e6403361ef91154d89fe \ + --hash=sha256:3a48a5254d15a0ad050318bfc7a9566d4ec740118187e8f303e47a6840287eb7 \ + --hash=sha256:3b8ee2589a082739c522c1fe4be227412fcf108b903abb6672ae2f5570558882 \ + --hash=sha256:3de6c2a4df2af0ac9ab4dc1488746fe8b1a90e27955d870d9edda3187d20092b \ + --hash=sha256:3e0b395648c6cb871bceb2906907f255dc876ec425f2d5b024e129985cea8519 \ + --hash=sha256:3e547ceec1da7382f01f9e13963023e53367a71802c88778b21b9645a077cbdf \ + --hash=sha256:41b2cd8b29dbb5a4c9828a70f50d1abfc92011115c813213d3a91205c6f731b3 \ + --hash=sha256:41f4f8ae714e4fea1d635880f8a1af715ecf080eed4d13c5b04a0f3210f9c61a \ + --hash=sha256:474f7e598c7902165662a5d5160d3fce31037890a2975a9871ebf7c05862300b \ + --hash=sha256:477af785d1846e4e96bf56983b92ea7553aaeccdeb8acdaa55c7cee9eda0ae32 \ + --hash=sha256:49eb1241a969a5994db6880c18c012b6cbe2340343d8f529721571806583e500 \ + --hash=sha256:4c29b8f2d6417069bb1f257e6b9113f5d64dc2f554cc200ea90b4fe2c5cdb733 \ + --hash=sha256:4eb15be588407148ef5937dc8d9256a71f6b115e6cddadb7aa20b6ee384680dc \ + --hash=sha256:4eda7e3fdef382b7d4492745988a5baaf6953923a337f8b9dde5f76fa8afde20 \ + --hash=sha256:523466eba8ee10f7480f3c2057563145978011c583130d2cc01fb1e7af808e25 \ + --hash=sha256:57fa0a9490785139f1a4e4f43891830d55dfe4408845c0c9cb5eff4aeaf75f69 \ + --hash=sha256:5b26e5f1793b96cdc60242bf38da86ff24a27a708aa396214cac9b534bf571c7 \ + --hash=sha256:5bc1811ef2b4d4ba63e8e452f6e332b6374bd1d2cbbfdf66826c8cb1f71dd10d \ + --hash=sha256:5c074454dc6d4f6f4ba6561a56bf33a14db7651d882a5a5321ba3ae8868e082d \ + --hash=sha256:5c1013647be741647895c102831dcf79c34209662dbb683df9efb864417ed7d5 \ + --hash=sha256:601fce6cea9ddeaa85329e12e7f351def38d233075f42a3012b9c48071b02941 \ + --hash=sha256:6118e5a5550e36582e19bac1a403711a748f9f18251b054c326d3db02aaa7a18 \ + --hash=sha256:629eae995185540406e3635df5d5cf1d44f19ea240840b835d3f44541ff694d8 \ + --hash=sha256:6348ad12fa741bcc9c2f173e99fbf27cbc038826d8c31a4a7d836eca27878ba2 \ + --hash=sha256:65376dbe1ab4dbc768ca2b72b7c13993562c035f5925fd3bc7ff9c8c585c515d \ + --hash=sha256:6619d49a89a15cd04334f76fec530c155923bfc60da74ff5d815a52629e1aa6c \ + --hash=sha256:664e74848c2f5fc27db8505fe24e1ecd3ac669412913bf73d176916f86cc08e2 \ + --hash=sha256:67f7cc397e1d5556a801d1cba74de0d27d827eb242e6c036c0ca273c745414f1 \ + --hash=sha256:696613a0c0e7b2b35356e389ba4195ce20cfe7a2fc2e992c87d974d973eabec7 \ + --hash=sha256:6c5687b59b6ba0f663c4f2f15470f68507d6b45ccd3a19ee6d224f95cbee70d8 \ + --hash=sha256:6c7d7b0b596319e9ce79ef96ce57a14054a2eac629c0588a0539187a218be799 \ + --hash=sha256:70dbc9f83c41f37a4faa62dae5203853847223a891da446f48ef2efcfd5df806 \ + --hash=sha256:71395a43da5584bb70556f380387e15f845c0dcf76373c1afbfa0025737576ac \ + --hash=sha256:71ade6d2e445839350d589ff99bbddfde16f3f32db28da5c894a09f99c8b2a03 \ + --hash=sha256:71e03d2ea1a221d020cfc5b6cc8bbbedef23a06704c70fcf4d0afb42965b22d1 \ + --hash=sha256:7210398a1607ad607dc73196e575b3148b00a333cbb602ddbe1b60ba54554f43 \ + --hash=sha256:7472c39480ccc11dda69a196d1b7c7a6b48eb6594b77f05d945599d3e47f731c \ + --hash=sha256:7646353a5a7c553c04167aca628e2550b538f492765b03ccf34321a560acc43c \ + --hash=sha256:76e0065998159244ff4c097a6c05ff08019c6fbb6e597a85846e73044f0215b3 \ + --hash=sha256:789a6453e5ffd18a7ab6b8c3a0dd8403053829197ec258ecb90c604c21ffcc99 \ + --hash=sha256:789f88dea57841cdebef392b5d6e90444d767117e9ff2e0d9172df5c9de6690c \ + --hash=sha256:7ac2769a7ddd661e07e26c12220adc31b17014c48234b2a5a88993b8d4109e09 \ + --hash=sha256:817953730e4a73a09008b010c4a42396cefe799616a22df2ac21d3927b3080cf \ + --hash=sha256:83d2beac85b757bfc404c5c0612df51c4ef33bbb7be65cf4a96b4da7cbc4ff4f \ + --hash=sha256:86c7c4615634b5c57a79770f5b738354e45ae219a89949aeae84f19169a05283 \ + --hash=sha256:8923fcd49f875e8a0448d7223d1fdf1a9973ae2d1f20d4158753ceb8909facd2 \ + --hash=sha256:8cceae48ae7f94990c2f4e36291e9ec9868735e8b0f19e4489a17b0422338466 \ + --hash=sha256:92f8f63df729061bb14558ed740e7a222f6e2aa6c2e6a5bcfb4e706676562049 \ + --hash=sha256:930ad463d3fb7a340d323bcc496ec32dae469ec9974c29ff569f19806b6b03b4 \ + --hash=sha256:94733cb447c37b0ce6f71b39ca1288d5f966a084023a5617b4cc35a852586859 \ + --hash=sha256:9be1cfe715ecaa060ffd5d599ef410b94ef2697a0eed4cee562f788a2aa2175b \ + --hash=sha256:a0c5210d038418a115e7cf8706bfa611bd14add2f5787274dba45aadca3155e0 \ + --hash=sha256:a2f8716344bbbd10443391be0b1f2003b34949e3c4e6883005c2bc498ab6b64b \ + --hash=sha256:a4bb174bd65f795c39ad6642d9d5bdc43351b306b7d0a654ab0d0abb38be245f \ + --hash=sha256:a70d5effebd81ebd8e15a8aabdc7980832367b2b00c36543bac378977004cc80 \ + --hash=sha256:a9ee990bf2cfbd81574c5d4f9f6c9d480a14b5b43d2c4f2ca13f4c6f48089394 \ + --hash=sha256:ab2822bcdcefb54d1e8ca29f5e3ec3afe160fb794bb3a3a73b09d11ed2671104 \ + --hash=sha256:ad92d255a165cde5f9882ff69699eaf5495e0a1f32e97566bbbb80f11e46781f \ + --hash=sha256:aead3b74b68396bf0feab5d57e050b730ded7df55853c1e048a87e00aaf033c6 \ + --hash=sha256:aeb2e123cbf978a905e9f55155c1b8316fbbfa7cf64d04521fe174bab302d100 \ + --hash=sha256:aec3c2d741a8e3ee993de7f95f37afb51e31b169c95dbd29da4cf6688f340914 \ + --hash=sha256:b0cdb655fbd1562c2dfc9986f9103a106f7058cd0915afc6e656d4b1d73f3387 \ + --hash=sha256:b26f39a5be3cd91a2035818be3d0ffdf5282c3e1f5f53d3b80b7024021acee52 \ + --hash=sha256:b2f2d13239487cecaae98c9f4d5904ad0737643cdf8873c88ec6a78b12214f20 \ + --hash=sha256:b300a30304c4c6aeab03ed06809819d9eceacdd58441d3c7dffe41edfd006091 \ + --hash=sha256:b42f64825f5d750228f08318a9bf4d723b7ecb4c472aedcb3013c3ec2dc1f949 \ + --hash=sha256:b67d38e8bb0ade7e6e84575e4bb153fab35b122458077273aeb08fdf12be9d2c \ + --hash=sha256:b867f9fd183d76977f810c626d539265183c25b2284762893a31e8d6cacc81c0 \ + --hash=sha256:b99bed995ed7c41515c11fe2beb86f8a6cc298e5537cae2f736de2f982f74ef0 \ + --hash=sha256:bd46bcc28ed85d3cf71581b42d90b4ebd1f2062f81879519fed209f8a4d1cfc6 \ + --hash=sha256:bee28aab5a580eec673f7b68dfa8dece3dd37bd207ef8d22fafe23a8e9837296 \ + --hash=sha256:c04e9d920e2674f54651fd260a15c5d2843526c73d5242ee4311325ddc9573b3 \ + --hash=sha256:c4c5a1770ecfe8bdb6c6f09f8d81ea4de04f7efb012fac1efa4ad315dccc1fd1 \ + --hash=sha256:c733087ecf7dde06b1d071679bfd5f3ba03266ba77814c1c7253bc48c9adedd9 \ + --hash=sha256:c813ada7a651193acda85b6bc1cf12abd4b37cd25c7c6a75d7183512cc374969 \ + --hash=sha256:c81d98e27d9d9261909dcccab1ba5d6ea1c98b0bb9470e368604614fd1d36ddd \ + --hash=sha256:c81e35862aced259177a537ce1a6264c3a97bae1ced184ca9dc10ea754563688 \ + --hash=sha256:c856e439a9d54d514e81a7131229ba151cdf81df7c408e0f6c89340e5003dfe2 \ + --hash=sha256:c9e70012926e97069cdd09221861aff412aa94e4cac2e019055cdb79485b150c \ + --hash=sha256:ca83a32b2b41653d89f09a3d22b770bca96da72273bef8f7a68136bdd1e8b823 \ + --hash=sha256:cbf0777d54672990b10cb8ca9b0523499e182d7e2ea39f86b138519a902aa601 \ + --hash=sha256:d49127f137f871cde3c5650af33bbbdcee02679dae76e020902fa106f522b8ae \ + --hash=sha256:d690121e80ab16e623415351ab24713534d4e500b3cadff216409cb6826063d4 \ + --hash=sha256:d6a166978f22f10cb91413f70519861605219346decf65bc79008f9257c94afe \ + --hash=sha256:d6e3485a5e5c01fb5339c1ee3d4b9e21e2135a2a9d44caafb71acd994487ee7c \ + --hash=sha256:d7d406709ae924cf0b08b8282ca2f0e1c90526911d93bc040557cbc83b74c55f \ + --hash=sha256:d8201c9f9035520cdcc7dcad383b039ec8123969b87e01cf27c3dd883c02313b \ + --hash=sha256:da779ae50b46f3f7d1e1b5f362fdc0ad376a49fd55f6f3122dc2b6149936cdf7 \ + --hash=sha256:dcf2c7eaaa4cafe8e49b017e5bb49e76e084ab6f0cd712ee4019c812b5cf68b8 \ + --hash=sha256:dd8bed00731a21e3106e5dd6bbffb6c775a2c0bbc7c0c9face534d830057bdc9 \ + --hash=sha256:df1c174796cd63eb6b139f7daf783affe1f3ed659605850e843b24764c21bfc5 \ + --hash=sha256:dfcf6e51000b34f7026322cd9ea9bc340d745637e27e0bbc22f504b4f6b967ee \ + --hash=sha256:e498900bfbf7ddddd862f810440c09e9b81674739e8a11d619b40906dccd4a9a \ + --hash=sha256:e512c75ec5cf4475c1aa50ad975ecdf253f4963b06e152e1a11edd6de4010753 \ + --hash=sha256:e5bd109d095aaae989a0463d5ef0fcc43e9ddd5de125e656d3c119a79e466380 \ + --hash=sha256:e6b4b08d09054310a4dc389fa61ee22a7a5a292cb23ab8a985136ca8828bf924 \ + --hash=sha256:e6da138a1ecc1341c8b788a5ee822670b03788e1f5decf7af9d461de6e508b8e \ + --hash=sha256:ea2f61b0bc12f3592288503961b764579dea0658852d96a0b3d823614d808821 \ + --hash=sha256:ed9c0b6f236648dbf30d57e9f57e1f74878caafa04833a19f529b5ba5164b7a8 \ + --hash=sha256:edbca8789fd10f0de534b660a6b4c71f1fd18039679c918dad392ab044bb37e4 \ + --hash=sha256:edc17549ab592e33cfcaf285f047bb75fcd98f608aa9309af1187fd736ce9641 \ + --hash=sha256:ef8a9ddb2e2a4eae4abb72dc0710eca6c2726779b0664bd10c3ce9fcfaed8c4e \ + --hash=sha256:f08ee8248aad2d054e5bc4c73554d4505464698f6d754f16198dbc5764e9821d \ + --hash=sha256:f1d62fb172db35c6478c9323da34ff37d1f3d37d7d44337a9d94ba8c583e5730 \ + --hash=sha256:f8fd23653a252cefabea11cd041efd7b80bdf403e43a36dea53f9cb0aaa21f0f \ + --hash=sha256:faa4e96385c820ce9d7f7a623486e23d4134ae3c9ba2071e44e0ab5a5a5002c4 \ + --hash=sha256:fb2bb5b557080da398b866408117d98fe9731a12334afd0cdff221b458cdc5dc \ + --hash=sha256:fc04affef30be98c1f36f0c422a4061ef618fdc1dde79f5ad5458dd496fecffa \ + --hash=sha256:ffb616d8d55965839670301dc3bae3abacff560a7e137a89056058a8a9da4d96 + # via + # idf-component-manager + # pydantic +pydantic-settings==2.16.2 \ + --hash=sha256:3dc08ffabed2bbd5dc2dd55ead7b78b4e4c5cd776aecd04310db5f1224caaf46 \ + --hash=sha256:8d523e5c129b097686bde019bd6109bff53f4c8c3f63f1ddf9933ffa42e5ab4f + # via idf-component-manager +pygments==2.21.0 \ + --hash=sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9 \ + --hash=sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c + # via rich +pyparsing==3.3.3 \ + --hash=sha256:928ae7e20211f3b6f3915a72f06a0cfd29ab9d24279dd6346b6b1a7146397d36 \ + --hash=sha256:ece8c00a69cf01b45d0b1dedabb469c90d8caf996d4fda40f147627a122849a4 + # via idf-component-manager +python-dotenv==1.2.4 \ + --hash=sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc \ + --hash=sha256:f0d53e69935a851c0dcc78f3ab7aaccd8cabef0b92382b576b824212902873c0 + # via pydantic-settings +requests==2.34.2 \ + --hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0 \ + --hash=sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed + # via + # idf-component-manager + # requests-file + # requests-toolbelt +requests-file==3.0.1 \ + --hash=sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2 \ + --hash=sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576 + # via idf-component-manager +requests-toolbelt==1.0.0 \ + --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ + --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 + # via idf-component-manager +rich==15.0.0 \ + --hash=sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb \ + --hash=sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36 + # via + # esp-pylib + # idf-component-manager + # rich-click +rich-click==1.9.9 \ + --hash=sha256:324cba7513cd4187ee92b2eef21f071714e45be062458c8b157bd7e0c81103e3 \ + --hash=sha256:365e7a9d0adb42e41ea832a0a12e02c44c079a26536dee688125eb9814f97274 + # via idf-component-manager +ruamel-yaml==0.19.1 \ + --hash=sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93 \ + --hash=sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993 + # via idf-component-manager +truststore==0.10.5 \ + --hash=sha256:30d36967ccaded5cbb38d602c433f53600036c79d502f4533a49b60a03bbefcd \ + --hash=sha256:9aaaedaefaf06d8b206278cf8b5012bc897f485a874503501e12d776df78951c + # via idf-component-manager +typing-extensions==4.16.0 \ + --hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \ + --hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5 + # via + # idf-component-manager + # pydantic + # pydantic-core + # pydantic-settings + # typing-inspection +typing-inspection==0.4.5 \ + --hash=sha256:7f16c411e7930dc79596d42ab44672a3fe5f60eb34b781a1647e7872363120c7 \ + --hash=sha256:bc210535442b39e1bf2805e0c7a17dfd6a4ace760c84c7f7d16245d23a6b1c39 + # via + # pydantic + # pydantic-settings +urllib3==2.8.0 \ + --hash=sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3 \ + --hash=sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63 + # via requests diff --git a/.ci/scripts/test_espressif_idf_nightly.sh b/.ci/scripts/test_espressif_idf_nightly.sh index d0b963921cb..36bb3fe95d9 100755 --- a/.ci/scripts/test_espressif_idf_nightly.sh +++ b/.ci/scripts/test_espressif_idf_nightly.sh @@ -5,13 +5,15 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -# The ExecuTorch ESP-IDF component's nightly matrix. +# The ExecuTorch ESP-IDF component's nightly matrix and release checks. # -# test_espressif_idf_nightly.sh prepare +# test_espressif_idf_nightly.sh prepare [stamp options] # In the ExecuTorch environment: exports the test models (smoke, the # esp_nn:: mul, an ESP-NN delegate program and the Cadence-quantized wake -# word), generates and packs the component into a file:// component mirror, -# and makes each model's kernel bundle, all under . all_ops is the +# word), generates the component with build_idf_component.sh's stamp +# options (default --allow-dev-stamp), packs it into /dist and a +# file:// component mirror, and makes each model's kernel bundle, all under +# . all_ops is the # smoke model with a bundle that registers every op of every kernel # library. # test_espressif_idf_nightly.sh build @@ -22,12 +24,19 @@ # own Python environment, checks that each configuration's settings took # effect, and runs each build on its emulator unless the rules disable its # test. Reports every failure, then fails. +# test_espressif_idf_nightly.sh registry +# Needs only from prepare: installs ESP-IDF 6.1, waits up to 15 +# minutes for the given component registry to list 's version of +# pytorch/executorch, builds the smoke consumer for ESP32-S3 with it, fails +# if the registry serves files other than 's archive, and runs the +# build on the emulator. set -euo pipefail et_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) -mode=${1:?usage: $0 prepare | build } -dir=${2:?usage: $0 prepare | build } +usage="usage: $0 prepare [stamp options] | build | registry " +mode=${1:?${usage}} +dir=${2:?${usage}} mkdir -p "${dir}" dir=$(cd "${dir}" && pwd) cd "${et_root}" @@ -45,6 +54,12 @@ logged() { } prepare() { + local stamp=("${@:3}") + if (( ${#stamp[@]} == 0 )); then + stamp=(--allow-dev-stamp) + fi + # Checks the stamp against git before the model exports. + bash examples/espressif/build_idf_component.sh --version "${stamp[@]}" > /dev/null export ESPRESSIF_TOOLS_DIR="${ESPRESSIF_TOOLS_DIR:-${RUNNER_TEMP:-/tmp}/executorch-espressif}" local logs="${dir}/logs" models="${dir}/models" mkdir -p "${logs}" "${models}" @@ -75,11 +90,13 @@ print(entry["atol"], entry["rtol"]) rm -r "${models}"/*.bpte "${dir}/espnn" local component_dir="${dir}/component/executorch" - logged "${logs}/generate.log" bash examples/espressif/build_idf_component.sh \ - --allow-dev-stamp --out "${component_dir}" + logged "${logs}/generate.log" bash examples/espressif/build_idf_component.sh "${stamp[@]}" \ + --out "${component_dir}" local version version=$(sed -n 's/^version: "\(.*\)"$/\1/p' "${component_dir}/idf_component.yml") - (cd "${component_dir}" && compote component pack --name executorch --dest-dir "${dir}/dist") + # The registry links each version to its commit and to the generator. + (cd "${component_dir}" && compote component pack --name executorch --dest-dir "${dir}/dist" \ + --commit-sha "$(git -C "${et_root}" rev-parse HEAD)" --repository-path examples/espressif) python .ci/scripts/esp_idf_mirror.py "${dir}/dist/executorch_${version}.tgz" "${dir}/mirror" \ --namespace pytorch --name executorch local model @@ -112,38 +129,16 @@ build() { mkdir -p "${work}" work=$(cd "${work}" && pwd) - # ESP-IDF's QEMU needs these libraries, and setup.sh fails its install check - # without them. - if ! python -c ' -import ctypes -ctypes.CDLL("libSDL2-2.0.so.0") -ctypes.CDLL("libslirp.so.0")' 2> /dev/null; then - sudo apt-get update - sudo apt-get install -y --no-install-recommends libsdl2-2.0-0 libslirp0 - fi - logged "${work}/setup.log" bash examples/espressif/setup.sh --minimal \ - --idf-version="${idf_version}" --targets="$(IFS=,; echo "${targets[*]}")" - # shellcheck source=/dev/null - source "${ESPRESSIF_TOOLS_DIR}/setup_path.sh" - - # A fresh ESP-IDF Python environment, which cannot import executorch, and + install_idf "${idf_version}" "$(IFS=,; echo "${targets[*]}")" "${work}" # idf-build-apps in a venv of its own, so it changes nothing ESP-IDF runs. - export IDF_PYTHON_ENV_PATH="${work}/idf_python_env" - mkdir -p "${IDF_PYTHON_ENV_PATH}" - logged "${work}/idf_python_env.log" python "${IDF_PATH}/tools/idf_tools.py" install-python-env "${IDF_PYTHON_ENV_PATH}/bin/python" -m venv "${work}/idf_build_apps" "${work}/idf_build_apps/bin/python" -m pip install --quiet "idf-build-apps>=3.1,<4" export IDF_COMPONENT_STORAGE_URL="file://${dir}/mirror;default" local version version=$(cat "${dir}/version") - # Built from a copy, so the component manager's state and the consumer's - # generated manifest stay out of the source tree. local sources="${work}/sources" - rm -rf "${sources}" - mkdir -p "${sources}/examples/espressif/idf_component_smoke" - cp -r examples/espressif/idf_component_consumer "${sources}/examples/espressif/" - cp -r examples/espressif/idf_component_smoke/main "${sources}/examples/espressif/idf_component_smoke/" + copy_consumer "${sources}" local app=examples/espressif/idf_component_consumer (cd "${sources}" && "${work}/idf_build_apps/bin/idf-build-apps" find -p "${app}" --target all \ --default-build-targets "${targets[@]}" --config-rules 'sdkconfig.ci.*=' \ @@ -200,6 +195,12 @@ PY failures+=("${name} (run)") fi done 3< "${work}/shard.txt" + # Exercises the check that registry mode runs after an upload. + if [[ -d "${project}/managed_components/pytorch__executorch" ]] \ + && ! served_matches "${dir}/dist/executorch_${version}.tgz" \ + "${project}/managed_components/pytorch__executorch" "the mirror"; then + failures+=("served files") + fi if (( ${#failures[@]} )); then printf 'FAIL: %s\n' "${failures[@]}" >&2 @@ -208,6 +209,133 @@ PY echo "PASS: shard ${shard}/${shards} of the ESP-IDF ${idf_version} matrix built and ran." } +# Installs ESP-IDF for the targets and makes a fresh ESP-IDF Python +# environment, which cannot import executorch: ESP-IDF version, comma-separated +# targets, work dir. +install_idf() { + local idf_version=$1 targets_csv=$2 work=$3 + # ESP-IDF's QEMU needs these libraries, and setup.sh fails its install check + # without them. + if [[ ",${targets_csv}," == *,esp32,* ]] && ! python -c ' +import ctypes +ctypes.CDLL("libSDL2-2.0.so.0") +ctypes.CDLL("libslirp.so.0")' 2> /dev/null; then + sudo apt-get update + sudo apt-get install -y --no-install-recommends libsdl2-2.0-0 libslirp0 + fi + logged "${work}/setup.log" bash examples/espressif/setup.sh --minimal \ + --idf-version="${idf_version}" --targets="${targets_csv}" + # shellcheck source=/dev/null + source "${ESPRESSIF_TOOLS_DIR}/setup_path.sh" + export IDF_PYTHON_ENV_PATH="${work}/idf_python_env" + mkdir -p "${IDF_PYTHON_ENV_PATH}" + logged "${work}/idf_python_env.log" python "${IDF_PATH}/tools/idf_tools.py" install-python-env +} + +# Copies the consumer project to a directory, so the component manager's state +# and the consumer's generated manifest stay out of the source tree. +copy_consumer() { + local sources=$1 + rm -rf "${sources}" + mkdir -p "${sources}/examples/espressif/idf_component_smoke" + cp -r examples/espressif/idf_component_consumer "${sources}/examples/espressif/" + cp -r examples/espressif/idf_component_smoke/main "${sources}/examples/espressif/idf_component_smoke/" +} + +registry() { + local registry_url=${3:?${usage}} + local work="${ESPRESSIF_BUILD_DIR:-${et_root}/cmake-out-esp-idf-registry}" + export ESPRESSIF_TOOLS_DIR="${ESPRESSIF_TOOLS_DIR:-${RUNNER_TEMP:-/tmp}/executorch-espressif}" + mkdir -p "${work}" + work=$(cd "${work}" && pwd) + install_idf v6.1 esp32s3 "${work}" + local version + version=$(cat "${dir}/version") + local storage + if ! storage=$(curl -sSf --retry 3 "${registry_url%/}/api/" | python -c ' +import json, sys +print(json.load(sys.stdin)["components_base_url"].rstrip("/"))'); then + echo "FAIL: ${registry_url}/api/ did not name the registry's storage" >&2 + exit 1 + fi + # The registry's storage is behind a CDN that caches for five minutes. + local tries=0 + until curl -sSf "${storage}/components/pytorch/executorch.json" 2> /dev/null | python -c ' +import json, sys +try: + versions = [v["version"] for v in json.load(sys.stdin)["versions"]] +except ValueError: + versions = [] +sys.exit(sys.argv[1] not in versions)' "${version}"; do + if (( ++tries == 30 )); then + echo "FAIL: ${registry_url} did not list pytorch/executorch ${version}" >&2 + exit 1 + fi + echo "Waiting for ${registry_url} to list pytorch/executorch ${version}..." + sleep 30 + done + copy_consumer "${work}/sources" + local project="${work}/sources/examples/espressif/idf_component_consumer" + local build="${work}/builds/esp32s3-default" log="${work}/emulator.log" + local idf_args=(-C "${project}" -B "${build}" -DSDKCONFIG="${build}/sdkconfig" + "-DSDKCONFIG_DEFAULTS=sdkconfig.defaults;sdkconfig.ci.default" + -DET_COMPONENT_VERSION="${version}" -DET_CONSUMER_MODELS_DIR="${dir}/models" + -DET_COMPONENT_REGISTRY_URL="${registry_url}") + IDF_TARGET=esp32s3 logged "${work}/build.log" "${IDF_PYTHON_ENV_PATH}/bin/python" \ + "${IDF_PATH}/tools/idf.py" "${idf_args[@]}" build + # --allow-existing uploads would not replace an archive already there. + served_matches "${dir}/dist/executorch_${version}.tgz" \ + "${project}/managed_components/pytorch__executorch" "${registry_url}" + local model + model=$(sed -n 's/^CONFIG_ET_CONSUMER_MODEL="\(.*\)"$/\1/p' "${build}/sdkconfig") + run_firmware "${build}" esp32s3 "${log}" "${idf_args[@]}" + if ! grep -qF "${model}: PASS" "${log}" || ! grep -qF "ET_COMPONENT_SMOKE: PASS" "${log}"; then + tail -n 30 "${log}" >&2 + echo "FAIL: the consumer from ${registry_url} did not pass on the emulator" >&2 + exit 1 + fi + echo "PASS: pytorch/executorch ${version} from ${registry_url} built and ran." +} + +# Checks that a project got the files of the tested archive from a registry or +# mirror: archive, the project's managed_components/pytorch__executorch, source. +# The registry rewrites the examples' manifests, dropping override_path, so +# those are the only files that may differ. +served_matches() { + python - "$@" <<'PY' +import hashlib +import sys +import tarfile +from pathlib import Path + + +def compared(path): + return path not in (".component_hash", "CHECKSUMS.json") and not ( + path.startswith("examples/") and path.endswith("/idf_component.yml") + ) + + +with tarfile.open(sys.argv[1]) as archive: + tested = { + Path(m.name).as_posix(): hashlib.sha256(archive.extractfile(m).read()).hexdigest() + for m in archive + if m.isfile() + } +served_dir = Path(sys.argv[2]) +served = { + p.relative_to(served_dir).as_posix(): hashlib.sha256(p.read_bytes()).hexdigest() + for p in served_dir.rglob("*") + if p.is_file() +} +differ = sorted( + p for p in tested.keys() | served.keys() if compared(p) and tested.get(p) != served.get(p) +) +if differ: + sys.exit(f"FAIL: {sys.argv[3]} served files unlike the tested archive's: {differ[:10]}") +print(f"OK: {sys.argv[3]} served the tested archive's files") +PY +} + # Checks that every setting of a sdkconfig.ci.* file reached the build's # sdkconfig, since ESP-IDF only warns about a symbol it does not know: # defaults file, sdkconfig. @@ -256,7 +384,8 @@ run_firmware() { } case "${mode}" in - prepare) prepare ;; + prepare) prepare "$@" ;; build) build "$@" ;; - *) echo "unknown mode ${mode}; use prepare or build" >&2; exit 1 ;; + registry) registry "$@" ;; + *) echo "unknown mode ${mode}; ${usage}" >&2; exit 1 ;; esac diff --git a/.ci/scripts/upload_espressif_idf_component.sh b/.ci/scripts/upload_espressif_idf_component.sh new file mode 100755 index 00000000000..2f1aecd19ba --- /dev/null +++ b/.ci/scripts/upload_espressif_idf_component.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Uploads the component archive that test_espressif_idf_nightly.sh prepare made +# to an ESP Component Registry as pytorch/executorch, and succeeds if the +# registry already has that version. +# +# upload_espressif_idf_component.sh [--dry-run] +# +# Without --dry-run the job needs `id-token: write`: like +# espressif/upload-components-ci-action, this authenticates with a GitHub OIDC +# token for the registry, which accepts it when the component's trusted +# uploader names this repository and the job's environment. --dry-run +# validates the archive and needs no token. + +set -euo pipefail + +usage="usage: $0 [--dry-run]" +if (( $# < 2 || $# > 3 )) || [[ $# == 3 && "$3" != --dry-run ]]; then + echo "${usage}" >&2 + exit 1 +fi +dir=$1 registry=$2 dry_run=("${@:3}") +version=$(cat "${dir}/version") + +python -m pip install --progress-bar off --require-hashes \ + -r "$(dirname "${BASH_SOURCE[0]}")/espressif_idf_upload_requirements.txt" +export IDF_COMPONENT_REGISTRY_URL="${registry}" +if (( ${#dry_run[@]} == 0 )); then + token=$(curl -sSfG --data-urlencode "audience=${registry}" \ + -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN:?needs id-token: write}" \ + "${ACTIONS_ID_TOKEN_REQUEST_URL}" | jq -er .value) + echo "::add-mask::${token}" + export IDF_COMPONENT_API_TOKEN="${token}" +fi +compote component upload --namespace pytorch --name executorch \ + --archive "${dir}/dist/executorch_${version}.tgz" --allow-existing "${dry_run[@]}" diff --git a/.github/workflows/nightly-espressif-idf.yml b/.github/workflows/nightly-espressif-idf.yml index be9142e1bdb..796e57d4798 100644 --- a/.github/workflows/nightly-espressif-idf.yml +++ b/.github/workflows/nightly-espressif-idf.yml @@ -13,6 +13,8 @@ on: - .ci/scripts/test_espressif_idf_nightly.sh - .ci/scripts/test_espressif_idf_configure.py - .ci/scripts/esp_idf_mirror.py + - .ci/scripts/upload_espressif_idf_component.sh + - .ci/scripts/espressif_idf_upload_requirements.txt - examples/espressif/build_idf_component.sh - examples/espressif/setup.sh - examples/espressif/export_smoke_model.py @@ -54,6 +56,10 @@ jobs: source .ci/scripts/utils.sh install_executorch --use-pt-pinned-commit --minimal bash .ci/scripts/test_espressif_idf_nightly.sh prepare "${RUNNER_ARTIFACT_DIR}" + # The release stamp's checks, which publishing otherwise first runs at a + # real tag, at a throwaway local one. + git tag -f "v$(cat version.txt)" + bash examples/espressif/build_idf_component.sh --version --version-suffix "" registry-dry-run: name: Registry validation (upload --dry-run) @@ -72,10 +78,8 @@ jobs: set -euo pipefail CONDA_ENV=$(conda env list --json | jq -r '.envs | .[-1]') conda activate "${CONDA_ENV}" - pip install --progress-bar off "idf-component-manager~=3.1" - version=$(cat "${RUNNER_ARTIFACT_DIR}/version") - compote component upload --namespace pytorch --name executorch \ - --archive "${RUNNER_ARTIFACT_DIR}/dist/executorch_${version}.tgz" --dry-run --allow-existing + bash .ci/scripts/upload_espressif_idf_component.sh "${RUNNER_ARTIFACT_DIR}" \ + https://components.espressif.com --dry-run build: name: ESP-IDF ${{ matrix.idf-version }} (${{ matrix.shard }}/4) diff --git a/.github/workflows/publish-esp-idf.yml b/.github/workflows/publish-esp-idf.yml new file mode 100644 index 00000000000..5ddc7518eb6 --- /dev/null +++ b/.github/workflows/publish-esp-idf.yml @@ -0,0 +1,292 @@ +name: Publish ESP-IDF component + +# Publishes pytorch/executorch to the ESP Component Registry: RC tags to the +# staging registry, release tags to staging and then production. The archive +# is built and tested on the ESP-IDF releases the component supports before +# any upload, and each upload is followed by a consumer build that resolves +# the version from that registry. See the release runbook in +# examples/espressif/README.md. + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + version_suffix: + description: 'Version suffix: empty at a release tag, -rc.N at an RC tag, ~N for a packaging respin on release/X.Y' + type: string + default: '' + registry: + description: 'Registry to publish to; production uploads to staging first' + type: choice + options: + - staging + - production + default: staging + dry_run: + description: 'Validate the archive with the registry without uploading' + type: boolean + default: true + pull_request: + paths: + - .github/workflows/publish-esp-idf.yml + - .ci/scripts/upload_espressif_idf_component.sh + - .ci/scripts/espressif_idf_upload_requirements.txt + +# Runs for one tag or branch go one at a time; runs for different ones, such as +# an RC awaiting approval and its release, do not hold each other up. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + plan: + name: Plan the release + runs-on: ubuntu-22.04 + outputs: + package: ${{ steps.plan.outputs.package }} + rehearsal: ${{ steps.plan.outputs.rehearsal }} + suffix: ${{ steps.plan.outputs.suffix }} + version: ${{ steps.plan.outputs.version }} + staging: ${{ steps.plan.outputs.staging }} + production: ${{ steps.plan.outputs.production }} + steps: + - id: plan + shell: bash + env: + EVENT: ${{ github.event_name }} + REF_NAME: ${{ github.ref_name }} + VERSION_SUFFIX: ${{ inputs.version_suffix }} + REGISTRY: ${{ inputs.registry }} + DRY_RUN: ${{ inputs.dry_run }} + run: | + set -euo pipefail + package=true rehearsal=false suffix='' version='' staging=false production=false + case "${EVENT}" in + push) + if [[ ! "${REF_NAME}" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)(-rc([1-9][0-9]*))?$ ]]; then + echo "::notice::${REF_NAME} is not a release or RC tag; nothing to publish." + package=false + elif [[ -n "${BASH_REMATCH[3]}" ]]; then + suffix="-rc.${BASH_REMATCH[3]}" version="${BASH_REMATCH[1]}-rc.${BASH_REMATCH[3]}" + staging=true + else + version="${BASH_REMATCH[1]}" staging=true production=true + fi + ;; + workflow_dispatch) + if [[ ! "${VERSION_SUFFIX}" =~ ^(-rc\.[1-9][0-9]*|~[1-9][0-9]*)?$ ]]; then + echo "::error::version_suffix must be empty, -rc.N or ~N, not '${VERSION_SUFFIX}'." + exit 1 + fi + if [[ "${VERSION_SUFFIX}" == -rc.* && "${REGISTRY}" == production ]]; then + echo "::error::release candidates go to the staging registry only." + exit 1 + fi + suffix="${VERSION_SUFFIX}" + if [[ "${DRY_RUN}" != true ]]; then + staging=true + [[ "${REGISTRY}" == production ]] && production=true + fi + ;; + *) + rehearsal=true + ;; + esac + { + echo "package=${package}" + echo "rehearsal=${rehearsal}" + echo "suffix=${suffix}" + echo "version=${version}" + echo "staging=${staging}" + echo "production=${production}" + } | tee -a "${GITHUB_OUTPUT}" + + docker-image: + name: Resolve CI docker image + needs: plan + if: needs.plan.outputs.package == 'true' + uses: ./.github/workflows/_docker-image.yml + + package: + name: Generate and pack the component + needs: [plan, docker-image] + uses: pytorch/test-infra/.github/workflows/linux_job_v3.yml@main + permissions: + id-token: write + contents: read + with: + runner: mt-l-x86iavx512-8-64 + docker-image: ${{ needs.docker-image.outputs.docker-registry }}/ci-image:executorch-ubuntu-22.04-clang12-${{ needs.docker-image.outputs.ci-docker-hash }} + submodules: recursive + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} + # The version stamp checks tags and, for a respin, release/X.Y's history. + fetch-depth: 0 + single-branch: false + timeout: 60 + upload-artifact: esp-idf-release + script: | + set -euo pipefail + CONDA_ENV=$(conda env list --json | jq -r '.envs | .[-1]') + conda activate "${CONDA_ENV}" + source .ci/scripts/utils.sh + install_executorch --use-pt-pinned-commit --minimal + if [[ "${{ needs.plan.outputs.rehearsal }}" == true ]]; then + # A pull request rehearses the release stamp at a throwaway local tag. + git tag -f "v$(cat version.txt)" + fi + # A tag names its version; a dispatch appends its suffix to version.txt. + expected="${{ needs.plan.outputs.version }}" + expected="${expected:-$(cat version.txt)${{ needs.plan.outputs.suffix }}}" + bash .ci/scripts/test_espressif_idf_nightly.sh prepare "${RUNNER_ARTIFACT_DIR}" \ + --version-suffix "${{ needs.plan.outputs.suffix }}" + version=$(cat "${RUNNER_ARTIFACT_DIR}/version") + if [[ "${version}" != "${expected}" ]]; then + echo "FAIL: generated version ${version}, expected ${expected}" >&2 + exit 1 + fi + echo "Packed pytorch/executorch ${version}" + # Nothing downstream reads the unpacked component. + rm -r "${RUNNER_ARTIFACT_DIR}/component" + + dry-run: + name: Registry validation on ${{ matrix.registry }} (upload --dry-run) + needs: [docker-image, package] + strategy: + fail-fast: false + matrix: + registry: [https://components-staging.espressif.com, https://components.espressif.com] + uses: pytorch/test-infra/.github/workflows/linux_job_v3.yml@main + permissions: + id-token: write + contents: read + with: + runner: mt-l-x86iavx512-8-64 + docker-image: ${{ needs.docker-image.outputs.docker-registry }}/ci-image:executorch-ubuntu-22.04-clang12-${{ needs.docker-image.outputs.ci-docker-hash }} + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} + timeout: 20 + download-artifact: esp-idf-release + script: | + set -euo pipefail + CONDA_ENV=$(conda env list --json | jq -r '.envs | .[-1]') + conda activate "${CONDA_ENV}" + bash .ci/scripts/upload_espressif_idf_component.sh "${RUNNER_ARTIFACT_DIR}" \ + "${{ matrix.registry }}" --dry-run + + build: + name: ESP-IDF ${{ matrix.idf-version }} (${{ matrix.shard }}/4) + needs: [docker-image, package] + strategy: + fail-fast: false + matrix: + idf-version: [v6.0.1, v6.1] + shard: [1, 2, 3, 4] + uses: pytorch/test-infra/.github/workflows/linux_job_v3.yml@main + permissions: + id-token: write + contents: read + with: + runner: mt-l-x86iavx512-8-64 + docker-image: ${{ needs.docker-image.outputs.docker-registry }}/ci-image:executorch-ubuntu-22.04-clang12-${{ needs.docker-image.outputs.ci-docker-hash }} + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} + timeout: 120 + download-artifact: esp-idf-release + script: | + set -euo pipefail + CONDA_ENV=$(conda env list --json | jq -r '.envs | .[-1]') + conda activate "${CONDA_ENV}" + ESPRESSIF_IDF_VERSION="${{ matrix.idf-version }}" \ + bash .ci/scripts/test_espressif_idf_nightly.sh build "${RUNNER_ARTIFACT_DIR}" \ + "${{ matrix.shard }}" 4 + + upload-staging: + name: Upload to the staging registry + needs: [plan, dry-run, build] + if: needs.plan.outputs.staging == 'true' + runs-on: ubuntu-22.04 + environment: esp-component-registry + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: esp-idf-release + path: ${{ runner.temp }}/esp-idf-release + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.11' + - run: | + bash .ci/scripts/upload_espressif_idf_component.sh "${RUNNER_TEMP}/esp-idf-release" \ + https://components-staging.espressif.com + + verify-staging: + name: Build the consumer from the staging registry + needs: [docker-image, upload-staging] + uses: pytorch/test-infra/.github/workflows/linux_job_v3.yml@main + permissions: + id-token: write + contents: read + with: + runner: mt-l-x86iavx512-8-64 + docker-image: ${{ needs.docker-image.outputs.docker-registry }}/ci-image:executorch-ubuntu-22.04-clang12-${{ needs.docker-image.outputs.ci-docker-hash }} + ref: ${{ github.sha }} + timeout: 60 + download-artifact: esp-idf-release + script: | + set -euo pipefail + CONDA_ENV=$(conda env list --json | jq -r '.envs | .[-1]') + conda activate "${CONDA_ENV}" + bash .ci/scripts/test_espressif_idf_nightly.sh registry "${RUNNER_ARTIFACT_DIR}" \ + https://components-staging.espressif.com + + upload-production: + name: Upload to the production registry + needs: [plan, verify-staging] + if: needs.plan.outputs.production == 'true' + runs-on: ubuntu-22.04 + environment: esp-component-registry + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: esp-idf-release + path: ${{ runner.temp }}/esp-idf-release + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.11' + - run: | + bash .ci/scripts/upload_espressif_idf_component.sh "${RUNNER_TEMP}/esp-idf-release" \ + https://components.espressif.com + + verify-production: + name: Build the consumer from the production registry + needs: [docker-image, upload-production] + uses: pytorch/test-infra/.github/workflows/linux_job_v3.yml@main + permissions: + id-token: write + contents: read + with: + runner: mt-l-x86iavx512-8-64 + docker-image: ${{ needs.docker-image.outputs.docker-registry }}/ci-image:executorch-ubuntu-22.04-clang12-${{ needs.docker-image.outputs.ci-docker-hash }} + ref: ${{ github.sha }} + timeout: 60 + download-artifact: esp-idf-release + script: | + set -euo pipefail + CONDA_ENV=$(conda env list --json | jq -r '.envs | .[-1]') + conda activate "${CONDA_ENV}" + bash .ci/scripts/test_espressif_idf_nightly.sh registry "${RUNNER_ARTIFACT_DIR}" \ + https://components.espressif.com diff --git a/examples/espressif/README.md b/examples/espressif/README.md index 0bd2c1a86ad..8d31fdb39ea 100644 --- a/examples/espressif/README.md +++ b/examples/espressif/README.md @@ -58,6 +58,51 @@ every op of every kernel library on ESP32-S3 and ESP32-C6. macOS and Windows jobs configure `idf_component_smoke` with the same component (`.github/workflows/nightly-espressif-idf.yml`). +### Publishing the component + +`.github/workflows/publish-esp-idf.yml` publishes the component to the ESP +Component Registry as `pytorch/executorch`. It packs the component once, +builds that archive in every `idf_component_consumer` configuration on +ESP-IDF 6.0.1 and 6.1, runs each build except the build-only one for +ESP32-P4 before rev3 on its emulator, and validates the archive with both +registries before uploading it. After each upload, a consumer build +resolves the new version from that registry, checks that the registry +serves the tested files, and runs it on the emulator. + +- An RC tag `vX.Y.Z-rcN` publishes `X.Y.Z-rc.N` to the staging registry, + https://components-staging.espressif.com. +- A release tag `vX.Y.Z` publishes `X.Y.Z` to staging, then to + https://components.espressif.com. +- A fix to the component after a release is a respin, `X.Y.Z~N`. Commit it + to `release/X.Y`, changing nothing since the tag outside + `examples/espressif/`, `.ci/`, `.github/` and `docs/`, and run the + workflow on `release/X.Y` with `version_suffix` `~N`. A release whose + publishing failed in CI is published as a respin once the CI is fixed. +- A manual run only validates unless `dry_run` is cleared. With `registry` + `production`, it uploads to staging first. Uploads skip versions the + registry already has, so **Re-run failed jobs** retries with the same + archive; **Re-run all jobs** packs a new one, which passes only if its + files match those the registry already serves. + +Each upload waits for a reviewer of the `esp-component-registry` +environment, the only place the registries accept uploads from: on each +registry, `pytorch/executorch`'s trusted uploader names this repository and +that environment. Before approving the staging upload, dispatch the nightly +matrix (`nightly-espressif-idf.yml`) on the tag and wait for it to pass; it +also covers ESP-IDF master, the all-ops build and the macOS and Windows +configure jobs. Approve the production upload once the release owner has +built a project against the version on staging. + +The one-time setup goes in this order, because GitHub creates a missing +environment, unprotected, as soon as a workflow names it: + +1. Create the `esp-component-registry` environment with required + reviewers, self-review prevented, no admin bypass, and deployments + limited to `v*` tags and `release/*` branches. +2. Create the `pytorch` namespace on the staging registry. +3. On each registry, make this repository and that environment + `pytorch/executorch`'s trusted uploader. + The executor runner below remains the reference for the prebuilt-library flow and for benchmarking. diff --git a/examples/espressif/idf_component_consumer/CMakeLists.txt b/examples/espressif/idf_component_consumer/CMakeLists.txt index 3aa1fba4d3e..f01705bf932 100644 --- a/examples/espressif/idf_component_consumer/CMakeLists.txt +++ b/examples/espressif/idf_component_consumer/CMakeLists.txt @@ -10,18 +10,26 @@ # project's ET_SMOKE_* variables, as .ci/scripts/test_espressif_idf_consumer.sh # does, or ET_CONSUMER_MODELS_DIR, from which CONFIG_ET_CONSUMER_MODEL (set by # the sdkconfig.ci.* configurations) picks the model, as -# .ci/scripts/test_espressif_idf_nightly.sh does. +# .ci/scripts/test_espressif_idf_nightly.sh does. ET_COMPONENT_REGISTRY_URL +# picks the registry instead of the component manager's default. cmake_minimum_required(VERSION 3.16) if(NOT ET_COMPONENT_VERSION) message(FATAL_ERROR "Set ET_COMPONENT_VERSION") endif() +set(ET_REGISTRY_LINE "") +if(ET_COMPONENT_REGISTRY_URL) + set(ET_REGISTRY_LINE "\n registry_url: ${ET_COMPONENT_REGISTRY_URL}") +endif() # The component manager reads main/idf_component.yml before any component's # CMakeLists.txt runs, and does not expand variables in versions. -file(CONFIGURE OUTPUT "${CMAKE_CURRENT_LIST_DIR}/main/idf_component.yml" - CONTENT - "dependencies:\n pytorch/executorch: \"==${ET_COMPONENT_VERSION}\"\n" +file( + CONFIGURE + OUTPUT + "${CMAKE_CURRENT_LIST_DIR}/main/idf_component.yml" + CONTENT + "dependencies:\n pytorch/executorch:\n version: \"==${ET_COMPONENT_VERSION}\"${ET_REGISTRY_LINE}\n" ) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(et_component_smoke) diff --git a/examples/espressif/idf_component_template/idf_component.yml.in b/examples/espressif/idf_component_template/idf_component.yml.in index 1bc3580f595..1496c2e89b2 100644 --- a/examples/espressif/idf_component_template/idf_component.yml.in +++ b/examples/espressif/idf_component_template/idf_component.yml.in @@ -22,4 +22,8 @@ tags: - inference dependencies: idf: ">=6.0" - espressif/esp-nn: "^1.4" + ## Named, because the staging registry records a dependency without a + ## registry_url as one of its own. + espressif/esp-nn: + version: "^1.4" + registry_url: https://components.espressif.com