From 21be1a1a854b2f35ddc574d8b8f50ed55a1bc23a Mon Sep 17 00:00:00 2001 From: "tgstation-server-ci[bot]" <161980869+tgstation-server-ci[bot]@users.noreply.github.com> Date: Sun, 18 Aug 2024 13:02:50 +0000 Subject: [PATCH] Deploy code docs to GitHub Pages for workflow run 3224 Commit: b0fa8e7c91f3ab39379da19d378ecacabce14a71 --- _byond_installer_base_8cs_source.html | 6 +- _delegating_engine_installer_8cs_source.html | 6 +- _dream_maker_8cs_source.html | 4 +- _engine_controller_8cs_source.html | 343 +-- _engine_installer_base_8cs_source.html | 6 +- _engine_manager_8cs_source.html | 852 ++++---- _fetch_options_extensions_8cs_source.html | 16 +- _i_dream_maker_8cs_source.html | 2 +- _i_engine_installer_8cs_source.html | 6 +- _i_engine_manager_8cs_source.html | 8 +- _i_process_base_8cs_source.html | 4 +- _i_repository_8cs_source.html | 14 +- _i_repository_manager_8cs_source.html | 8 +- _job_entrypoint_8cs_source.html | 2 +- _job_progress_reporter_8cs_source.html | 312 ++- _job_service_8cs_source.html | 194 +- _open_dream_installer_8cs_source.html | 471 +++-- _process_8cs_source.html | 442 ++-- _repository_8cs_source.html | 1864 +++++++++-------- _repository_manager_8cs_source.html | 16 +- _repository_update_service_8cs_source.html | 971 ++++----- _session_controller_8cs_source.html | 6 +- ...st_2_components_2_instance_8cs_source.html | 6 +- _watchdog_base_8cs_source.html | 4 +- _windows_open_dream_installer_8cs_source.html | 2 +- changelog.yml | 5 + class_i_disposable.html | 37 +- class_i_disposable__inherit__graph.map | 37 +- class_i_disposable__inherit__graph.md5 | 2 +- class_i_disposable__inherit__graph.png | Bin 298326 -> 306239 bytes ...1_1_api_1_1_models_1_1_engine_version.html | 20 +- ...76a2503f8e4371139e9abe80df44d2_icgraph.map | 6 +- ...76a2503f8e4371139e9abe80df44d2_icgraph.md5 | 2 +- ..._1_1_internal_1_1_repository_settings.html | 4 +- ..._server_1_1_api_1_1_models_1_1_limits.html | 2 +- ..._extensions_1_1_value_task_extensions.html | 2 +- ...onents_1_1_deployment_1_1_dream_maker.html | 4 +- ...gine_1_1_byond_installer_base-members.html | 2 +- ...s_1_1_engine_1_1_byond_installer_base.html | 42 +- ...0f9b30cccd75058679a819522f0b74_icgraph.map | 2 +- ...0f9b30cccd75058679a819522f0b74_icgraph.md5 | 2 +- ...f1546f8ef11d749bc75509ce63bdae5_cgraph.map | 0 ...f1546f8ef11d749bc75509ce63bdae5_cgraph.md5 | 0 ...f1546f8ef11d749bc75509ce63bdae5_cgraph.png | Bin ...1_delegating_engine_installer-members.html | 2 +- ...ngine_1_1_delegating_engine_installer.html | 26 +- ...ine_1_1_engine_installer_base-members.html | 2 +- ..._1_1_engine_1_1_engine_installer_base.html | 38 +- ...0a63f182a77bc1a099f3c7f8cd6849_icgraph.map | 4 +- ...0a63f182a77bc1a099f3c7f8cd6849_icgraph.md5 | 2 +- ...1_1_engine_1_1_engine_manager-members.html | 6 +- ...ponents_1_1_engine_1_1_engine_manager.html | 1036 ++++----- ...303d46d250191f69bb5251c89ca301d_cgraph.md5 | 1 - ...303d46d250191f69bb5251c89ca301d_cgraph.png | Bin 85220 -> 0 bytes ...03d46d250191f69bb5251c89ca301d_icgraph.md5 | 1 - ...d4c2604e3020f77b073021bf3016b4_icgraph.map | 2 +- ...d4c2604e3020f77b073021bf3016b4_icgraph.md5 | 2 +- ...d2a758adff2c72db49e822c8f6ceccf_cgraph.md5 | 1 - ...d2a758adff2c72db49e822c8f6ceccf_cgraph.png | Bin 126786 -> 0 bytes ...2a758adff2c72db49e822c8f6ceccf_icgraph.md5 | 1 - ...d0593064aa1c11835cfa1ab2823ec34_cgraph.map | 32 +- ...d0593064aa1c11835cfa1ab2823ec34_cgraph.md5 | 1 + ...d0593064aa1c11835cfa1ab2823ec34_cgraph.png | Bin 0 -> 155232 bytes ...0593064aa1c11835cfa1ab2823ec34_icgraph.map | 2 +- ...0593064aa1c11835cfa1ab2823ec34_icgraph.md5 | 1 + ...0593064aa1c11835cfa1ab2823ec34_icgraph.png | Bin ...03c2123e6edceee48d8b4897be532c6_cgraph.map | 36 +- ...03c2123e6edceee48d8b4897be532c6_cgraph.md5 | 2 +- ...03c2123e6edceee48d8b4897be532c6_cgraph.png | Bin 137052 -> 164267 bytes ...9978534a863e31d7d58e51c86b5886c_cgraph.map | 42 +- ...9978534a863e31d7d58e51c86b5886c_cgraph.md5 | 1 + ...9978534a863e31d7d58e51c86b5886c_cgraph.png | Bin 0 -> 184344 bytes ...06e9789785574f8d657a29fdd183795_cgraph.map | 20 +- ...06e9789785574f8d657a29fdd183795_cgraph.md5 | 1 + ...06e9789785574f8d657a29fdd183795_cgraph.png | Bin 0 -> 102272 bytes ...6e9789785574f8d657a29fdd183795_icgraph.map | 4 +- ...6e9789785574f8d657a29fdd183795_icgraph.md5 | 1 + ...6e9789785574f8d657a29fdd183795_icgraph.png | Bin ...40140865facd71ee580f625a8c95bc_icgraph.map | 4 +- ...40140865facd71ee580f625a8c95bc_icgraph.md5 | 2 +- ...2cedaccbf100b9dcf3922a9443f8f19_cgraph.md5 | 1 - ...2cedaccbf100b9dcf3922a9443f8f19_cgraph.png | Bin 169926 -> 0 bytes ...gine_1_1_open_dream_installer-members.html | 2 +- ...s_1_1_engine_1_1_open_dream_installer.html | 507 ++--- ...df90470a5fd85e870cf0d959181e7d8_cgraph.map | 8 - ...df90470a5fd85e870cf0d959181e7d8_cgraph.md5 | 1 - ...df90470a5fd85e870cf0d959181e7d8_cgraph.png | Bin 38513 -> 0 bytes ...0f999e3876ac5a4c9c92684df68ec12_cgraph.map | 11 + ...0f999e3876ac5a4c9c92684df68ec12_cgraph.md5 | 1 + ...0f999e3876ac5a4c9c92684df68ec12_cgraph.png | Bin 0 -> 68826 bytes ...ine_1_1_posix_byond_installer-members.html | 2 +- ..._1_1_engine_1_1_posix_byond_installer.html | 26 +- ...e_1_1_windows_byond_installer-members.html | 2 +- ..._1_engine_1_1_windows_byond_installer.html | 26 +- ..._windows_open_dream_installer-members.html | 2 +- ...gine_1_1_windows_open_dream_installer.html | 30 +- ..._1_1_host_1_1_components_1_1_instance.html | 283 +-- ...1cc04923d2557eefd57ad2ded9eb7f2_cgraph.md5 | 2 +- ...2340b0e0ecd2c2ccc812d88f86f7a3c_cgraph.map | 89 +- ...2340b0e0ecd2c2ccc812d88f86f7a3c_cgraph.md5 | 2 +- ...2340b0e0ecd2c2ccc812d88f86f7a3c_cgraph.png | Bin 468619 -> 460703 bytes ...6b97c61b214295da99e737ab2570b5a_cgraph.map | 91 +- ...6b97c61b214295da99e737ab2570b5a_cgraph.md5 | 2 +- ...6b97c61b214295da99e737ab2570b5a_cgraph.png | Bin 480223 -> 469720 bytes ...437eb5855fbd7575d4a5b0c71217745_cgraph.map | 2 +- ...437eb5855fbd7575d4a5b0c71217745_cgraph.md5 | 2 +- ...437eb5855fbd7575d4a5b0c71217745_cgraph.png | Bin 69632 -> 72568 bytes ...c1fd9e8dc3bd57b78dbcbc4e7f449b4_cgraph.map | 95 +- ...c1fd9e8dc3bd57b78dbcbc4e7f449b4_cgraph.md5 | 2 +- ...c1fd9e8dc3bd57b78dbcbc4e7f449b4_cgraph.png | Bin 498542 -> 485142 bytes ...1_1_repository_1_1_repository-members.html | 37 +- ...ponents_1_1_repository_1_1_repository.html | 1591 +++++++------- ...repository_1_1_repository__coll__graph.map | 3 +- ...repository_1_1_repository__coll__graph.md5 | 2 +- ...repository_1_1_repository__coll__graph.png | Bin 183140 -> 192586 bytes ...44a180597fe2bde35fd85e43d0dd59d_cgraph.map | 10 +- ...44a180597fe2bde35fd85e43d0dd59d_cgraph.md5 | 1 + ...44a180597fe2bde35fd85e43d0dd59d_cgraph.png | Bin 0 -> 51487 bytes ...28bfe68ce247974125194b074003c1b_cgraph.md5 | 1 - ...28bfe68ce247974125194b074003c1b_cgraph.png | Bin 17882 -> 0 bytes ...8bfe68ce247974125194b074003c1b_icgraph.md5 | 1 - ...a8561c6ba67a42fec9a9830a043fbdc_cgraph.map | 7 +- ...a8561c6ba67a42fec9a9830a043fbdc_cgraph.md5 | 2 +- ...a8561c6ba67a42fec9a9830a043fbdc_cgraph.png | Bin 69166 -> 69729 bytes ...dc9ca8cfb27f89f6d595412d819021a_cgraph.map | 6 +- ...dc9ca8cfb27f89f6d595412d819021a_cgraph.md5 | 2 +- ...dc9ca8cfb27f89f6d595412d819021a_cgraph.png | Bin 15081 -> 17096 bytes ...32cb5984c52022a23716cbabb1e4a40_cgraph.map | 9 + ...32cb5984c52022a23716cbabb1e4a40_cgraph.md5 | 1 + ...32cb5984c52022a23716cbabb1e4a40_cgraph.png | Bin 0 -> 46644 bytes ...fefc02e22b5c22787b498a045107740_cgraph.map | 7 +- ...fefc02e22b5c22787b498a045107740_cgraph.md5 | 1 + ...fefc02e22b5c22787b498a045107740_cgraph.png | Bin 0 -> 23487 bytes ...efc02e22b5c22787b498a045107740_icgraph.map | 2 +- ...efc02e22b5c22787b498a045107740_icgraph.md5 | 1 + ...efc02e22b5c22787b498a045107740_icgraph.png | Bin ...5068b3afe9edb4dc3a0474422f650aa_cgraph.map | 8 - ...5068b3afe9edb4dc3a0474422f650aa_cgraph.md5 | 1 - ...5068b3afe9edb4dc3a0474422f650aa_cgraph.png | Bin 40344 -> 0 bytes ...52e74ecb862a3cb6c26b89970ccc402_cgraph.md5 | 1 - ...52e74ecb862a3cb6c26b89970ccc402_cgraph.png | Bin 17853 -> 0 bytes ...a21ca98ea484845f3a7094fcc782814_cgraph.md5 | 1 - ...a21ca98ea484845f3a7094fcc782814_cgraph.png | Bin 38211 -> 0 bytes ...23395c46c6ba3e61646128d392d586b_cgraph.md5 | 1 - ...23395c46c6ba3e61646128d392d586b_cgraph.png | Bin 17556 -> 0 bytes ...3395c46c6ba3e61646128d392d586b_icgraph.md5 | 1 - ...63b639a5a6a59e780677f9849122b1f_cgraph.map | 4 + ...63b639a5a6a59e780677f9849122b1f_cgraph.md5 | 1 + ...63b639a5a6a59e780677f9849122b1f_cgraph.png | Bin 0 -> 11617 bytes ...97958179867ac2592eebd95711cf822_cgraph.map | 7 +- ...97958179867ac2592eebd95711cf822_cgraph.md5 | 1 + ...97958179867ac2592eebd95711cf822_cgraph.png | Bin 0 -> 23319 bytes ...7958179867ac2592eebd95711cf822_icgraph.map | 2 +- ...7958179867ac2592eebd95711cf822_icgraph.md5 | 1 + ...7958179867ac2592eebd95711cf822_icgraph.png | Bin ...e952092abaede9670adeaf6114d7d73_cgraph.map | 13 +- ...e952092abaede9670adeaf6114d7d73_cgraph.md5 | 2 +- ...e952092abaede9670adeaf6114d7d73_cgraph.png | Bin 45686 -> 46294 bytes ...ee48c4e5681a5003e8b626bfbbc2ef8_cgraph.map | 6 +- ...ee48c4e5681a5003e8b626bfbbc2ef8_cgraph.md5 | 1 + ...ee48c4e5681a5003e8b626bfbbc2ef8_cgraph.png | Bin 0 -> 17564 bytes ...sitory_1_1_repository_manager-members.html | 2 +- ...1_1_repository_1_1_repository_manager.html | 61 +- ...7aa1886c83c4ddb306ad33074f3a365_cgraph.md5 | 1 - ...7aa1886c83c4ddb306ad33074f3a365_cgraph.png | Bin 93800 -> 0 bytes ...40bff5e7feecd1e71018b1d6fab7bc_icgraph.map | 2 +- ...40bff5e7feecd1e71018b1d6fab7bc_icgraph.md5 | 2 +- ...d9235dfb77b745164af1553b922573d_cgraph.map | 19 +- ...d9235dfb77b745164af1553b922573d_cgraph.md5 | 1 + ...d9235dfb77b745164af1553b922573d_cgraph.png | Bin 0 -> 96717 bytes ...ository_1_1_repository_update_service.html | 982 ++++----- ...52e0821327fb59aa750db441622df34_cgraph.map | 8 +- ...52e0821327fb59aa750db441622df34_cgraph.md5 | 2 +- ...52e0821327fb59aa750db441622df34_cgraph.png | Bin 36135 -> 32935 bytes ...11d4f50183fc2f990b464da1fd0b240_cgraph.map | 15 +- ...11d4f50183fc2f990b464da1fd0b240_cgraph.md5 | 2 +- ...11d4f50183fc2f990b464da1fd0b240_cgraph.png | Bin 47869 -> 51941 bytes ..._1_1_repository_1_1_test_merge_result.html | 2 +- ...ession_1_1_session_controller-members.html | 2 +- ...ts_1_1_session_1_1_session_controller.html | 20 +- ...nfiguration_1_1_general_configuration.html | 2 +- ...nfiguration_1_1_session_configuration.html | 2 +- ...1_1_controllers_1_1_engine_controller.html | 325 +-- ..._1_1_fetch_options_extensions-members.html | 4 +- ...tensions_1_1_fetch_options_extensions.html | 49 +- ...e986ebc3ee757beadd72f98f99076c_icgraph.md5 | 1 - ...19e6ba4a3ccca999a74240886628b41_cgraph.md5 | 1 - ...b564fc1ab3f6caf84958bc85d5236a_icgraph.map | 2 +- ...b564fc1ab3f6caf84958bc85d5236a_icgraph.md5 | 1 + ...b564fc1ab3f6caf84958bc85d5236a_icgraph.png | Bin ...e0e1a7712aa907faf658940322b8478_cgraph.map | 2 +- ...e0e1a7712aa907faf658940322b8478_cgraph.md5 | 1 + ...e0e1a7712aa907faf658940322b8478_cgraph.png | Bin ..._host_1_1_i_o_1_1_default_i_o_manager.html | 4 +- ...obs_1_1_job_progress_reporter-members.html | 12 +- ...st_1_1_jobs_1_1_job_progress_reporter.html | 594 ++++-- ...1_1_job_progress_reporter__coll__graph.map | 13 +- ...1_1_job_progress_reporter__coll__graph.md5 | 2 +- ...1_1_job_progress_reporter__coll__graph.png | Bin 29853 -> 38056 bytes ..._job_progress_reporter__inherit__graph.map | 4 + ..._job_progress_reporter__inherit__graph.md5 | 1 + ..._job_progress_reporter__inherit__graph.png | Bin 0 -> 6698 bytes ...2254a185da6e76e7fcd2d72a8032970_cgraph.map | 4 +- ...2254a185da6e76e7fcd2d72a8032970_cgraph.md5 | 2 +- ...2254a185da6e76e7fcd2d72a8032970_cgraph.png | Bin 10028 -> 11568 bytes ...254a185da6e76e7fcd2d72a8032970_icgraph.map | 39 +- ...254a185da6e76e7fcd2d72a8032970_icgraph.md5 | 2 +- ...254a185da6e76e7fcd2d72a8032970_icgraph.png | Bin 141843 -> 187474 bytes ...e9230c68a7eff4ddf044bb8c07836cc_cgraph.map | 4 + ...e9230c68a7eff4ddf044bb8c07836cc_cgraph.md5 | 1 + ...e9230c68a7eff4ddf044bb8c07836cc_cgraph.png | Bin 0 -> 9209 bytes ...5af832a3c5781b796441234fc0e5fe_icgraph.map | 25 + ...5af832a3c5781b796441234fc0e5fe_icgraph.md5 | 1 + ...5af832a3c5781b796441234fc0e5fe_icgraph.png | Bin 0 -> 196024 bytes ...36a80d9d56a20711468d9b8e27e3c1_icgraph.map | 48 +- ...36a80d9d56a20711468d9b8e27e3c1_icgraph.md5 | 2 +- ...36a80d9d56a20711468d9b8e27e3c1_icgraph.png | Bin 239861 -> 151935 bytes ...ver_1_1_host_1_1_jobs_1_1_job_service.html | 188 +- ...1_security_1_1_authentication_context.html | 2 +- ...1_1_host_1_1_system_1_1_dotnet_helper.html | 2 +- ...1_host_1_1_system_1_1_process-members.html | 2 +- ...erver_1_1_host_1_1_system_1_1_process.html | 434 ++-- ..._host_1_1_system_1_1_process_executor.html | 2 +- ..._host_1_1_utils_1_1_reference_counter.html | 6 +- ...603269a01198b149ea66eaba0dd014_icgraph.map | 4 +- ...603269a01198b149ea66eaba0dd014_icgraph.md5 | 2 +- ...tils_1_1_reference_counting_container.html | 10 +- ...512890f504f0e2fa9593bbd5ab851f_icgraph.map | 4 +- ...512890f504f0e2fa9593bbd5ab851f_icgraph.md5 | 2 +- ..._1_1_utils_1_1_semaphore_slim_context.html | 6 +- ...773d588476671bbe480f096d839c91_icgraph.map | 4 +- ...773d588476671bbe480f096d839c91_icgraph.md5 | 2 +- functions.html | 8 +- functions_c.html | 13 +- functions_d.html | 4 +- functions_f.html | 2 +- functions_func.html | 2 +- functions_func_c.html | 6 +- functions_func_d.html | 6 +- functions_func_f.html | 2 +- functions_func_g.html | 2 +- functions_func_h.html | 2 +- functions_func_i.html | 2 +- functions_func_j.html | 2 +- functions_func_r.html | 2 +- functions_func_t.html | 2 +- functions_func_u.html | 2 +- functions_g.html | 6 +- functions_h.html | 9 +- functions_i.html | 6 +- functions_j.html | 4 +- functions_m.html | 2 +- functions_o.html | 2 +- functions_p.html | 5 +- functions_prop_m.html | 2 +- functions_r.html | 2 +- functions_s.html | 10 +- functions_t.html | 5 +- functions_u.html | 6 +- functions_vars_p.html | 1 + functions_vars_s.html | 1 + hierarchy.html | 550 ++--- index.html | 2 +- inherit_graph_156.map | 4 +- inherit_graph_156.md5 | 2 +- inherit_graph_156.png | Bin 4344 -> 17647 bytes inherit_graph_157.map | 7 +- inherit_graph_157.md5 | 2 +- inherit_graph_157.png | Bin 17647 -> 18886 bytes inherit_graph_158.map | 11 +- inherit_graph_158.md5 | 2 +- inherit_graph_158.png | Bin 18886 -> 36946 bytes inherit_graph_159.map | 12 +- inherit_graph_159.md5 | 2 +- inherit_graph_159.png | Bin 36946 -> 29445 bytes inherit_graph_160.map | 6 +- inherit_graph_160.md5 | 2 +- inherit_graph_160.png | Bin 29445 -> 5198 bytes inherit_graph_161.map | 2 +- inherit_graph_161.md5 | 2 +- inherit_graph_161.png | Bin 5198 -> 4159 bytes inherit_graph_162.map | 2 +- inherit_graph_162.md5 | 2 +- inherit_graph_162.png | Bin 4159 -> 4525 bytes inherit_graph_163.map | 2 +- inherit_graph_163.md5 | 2 +- inherit_graph_163.png | Bin 4525 -> 2720 bytes inherit_graph_164.map | 3 +- inherit_graph_164.md5 | 2 +- inherit_graph_164.png | Bin 2720 -> 9645 bytes inherit_graph_165.map | 5 +- inherit_graph_165.md5 | 2 +- inherit_graph_165.png | Bin 9645 -> 16662 bytes inherit_graph_166.map | 5 +- inherit_graph_166.md5 | 2 +- inherit_graph_166.png | Bin 16662 -> 8408 bytes inherit_graph_167.map | 4 +- inherit_graph_167.md5 | 2 +- inherit_graph_167.png | Bin 8408 -> 9215 bytes inherit_graph_168.map | 9 +- inherit_graph_168.md5 | 2 +- inherit_graph_168.png | Bin 9215 -> 40800 bytes inherit_graph_169.map | 8 +- inherit_graph_169.md5 | 2 +- inherit_graph_169.png | Bin 40800 -> 4088 bytes inherit_graph_170.map | 2 +- inherit_graph_170.md5 | 2 +- inherit_graph_170.png | Bin 4088 -> 3479 bytes inherit_graph_171.map | 2 +- inherit_graph_171.md5 | 2 +- inherit_graph_171.png | Bin 3479 -> 4179 bytes inherit_graph_172.map | 3 +- inherit_graph_172.md5 | 2 +- inherit_graph_172.png | Bin 4179 -> 5076 bytes inherit_graph_173.map | 4 +- inherit_graph_173.md5 | 2 +- inherit_graph_173.png | Bin 5076 -> 6278 bytes inherit_graph_174.map | 3 +- inherit_graph_174.md5 | 2 +- inherit_graph_174.png | Bin 6278 -> 4420 bytes inherit_graph_175.map | 2 +- inherit_graph_175.md5 | 2 +- inherit_graph_175.png | Bin 4420 -> 5149 bytes inherit_graph_176.map | 2 +- inherit_graph_176.md5 | 2 +- inherit_graph_176.png | Bin 5149 -> 4878 bytes inherit_graph_177.map | 2 +- inherit_graph_177.md5 | 2 +- inherit_graph_177.png | Bin 4878 -> 4909 bytes inherit_graph_178.map | 2 +- inherit_graph_178.md5 | 2 +- inherit_graph_178.png | Bin 4909 -> 3793 bytes inherit_graph_179.map | 3 +- inherit_graph_179.md5 | 2 +- inherit_graph_179.png | Bin 3793 -> 9803 bytes inherit_graph_180.map | 4 +- inherit_graph_180.md5 | 2 +- inherit_graph_180.png | Bin 9803 -> 9013 bytes inherit_graph_181.map | 4 +- inherit_graph_181.md5 | 2 +- inherit_graph_181.png | Bin 9013 -> 8304 bytes inherit_graph_182.map | 4 +- inherit_graph_182.md5 | 2 +- inherit_graph_182.png | Bin 8304 -> 8145 bytes inherit_graph_183.map | 3 +- inherit_graph_183.md5 | 2 +- inherit_graph_183.png | Bin 8145 -> 4294 bytes inherit_graph_184.map | 2 +- inherit_graph_184.md5 | 2 +- inherit_graph_184.png | Bin 4294 -> 4658 bytes inherit_graph_185.map | 2 +- inherit_graph_185.md5 | 2 +- inherit_graph_185.png | Bin 4658 -> 4246 bytes inherit_graph_186.map | 2 +- inherit_graph_186.md5 | 2 +- inherit_graph_186.png | Bin 4246 -> 4589 bytes inherit_graph_187.map | 4 +- inherit_graph_187.md5 | 2 +- inherit_graph_187.png | Bin 4589 -> 8539 bytes inherit_graph_188.map | 5 +- inherit_graph_188.md5 | 2 +- inherit_graph_188.png | Bin 8539 -> 9218 bytes inherit_graph_189.map | 4 +- inherit_graph_189.md5 | 2 +- inherit_graph_189.png | Bin 9218 -> 8540 bytes inherit_graph_190.map | 4 +- inherit_graph_190.md5 | 2 +- inherit_graph_190.png | Bin 8540 -> 8046 bytes inherit_graph_191.map | 3 +- inherit_graph_191.md5 | 2 +- inherit_graph_191.png | Bin 8046 -> 6478 bytes inherit_graph_192.map | 2 +- inherit_graph_192.md5 | 2 +- inherit_graph_192.png | Bin 6478 -> 4408 bytes inherit_graph_193.map | 3 +- inherit_graph_193.md5 | 2 +- inherit_graph_193.png | Bin 4408 -> 10192 bytes inherit_graph_194.map | 3 +- inherit_graph_194.md5 | 2 +- inherit_graph_194.png | Bin 10192 -> 9112 bytes inherit_graph_195.map | 2 +- inherit_graph_195.md5 | 2 +- inherit_graph_195.png | Bin 9112 -> 7322 bytes inherit_graph_196.map | 5 +- inherit_graph_196.md5 | 2 +- inherit_graph_196.png | Bin 7322 -> 26197 bytes inherit_graph_197.map | 6 +- inherit_graph_197.md5 | 2 +- inherit_graph_197.png | Bin 26197 -> 5272 bytes inherit_graph_198.map | 4 +- inherit_graph_198.md5 | 2 +- inherit_graph_198.png | Bin 5272 -> 5688 bytes inherit_graph_199.map | 4 - inherit_graph_199.md5 | 1 - inherit_graph_199.png | Bin 5688 -> 0 bytes inherit_graph_2.map | 323 +-- inherit_graph_2.md5 | 2 +- inherit_graph_2.png | Bin 1328458 -> 1362871 bytes inherits.html | 396 ++-- ..._1_1_engine_1_1_i_engine_installation.html | 2 +- ...engine_1_1_i_engine_installation_data.html | 8 +- ...12d13d543fde6cbb64c9085f9370b7_icgraph.map | 6 +- ...12d13d543fde6cbb64c9085f9370b7_icgraph.md5 | 2 +- ...engine_1_1_i_engine_installer-members.html | 2 +- ...nts_1_1_engine_1_1_i_engine_installer.html | 44 +- ...ac565523ae59fd18a8ad6eb1dfb616_icgraph.map | 4 +- ...ac565523ae59fd18a8ad6eb1dfb616_icgraph.md5 | 2 +- ...41dfb27438fbd4d70462cd137bcb42_icgraph.map | 6 +- ...41dfb27438fbd4d70462cd137bcb42_icgraph.md5 | 1 + ...41dfb27438fbd4d70462cd137bcb42_icgraph.png | Bin ...100637a7abd23c97157b7a4deb4736_icgraph.md5 | 1 - ...982c374c0d5d56779125fce7c933be_icgraph.map | 6 +- ...982c374c0d5d56779125fce7c933be_icgraph.md5 | 2 +- ...1_engine_1_1_i_engine_manager-members.html | 2 +- ...nents_1_1_engine_1_1_i_engine_manager.html | 16 +- ...nents_1_1_events_1_1_i_event_consumer.html | 10 +- ...4f82eb43566dabd77e37191b4e3d37_icgraph.map | 8 +- ...4f82eb43566dabd77e37191b4e3d37_icgraph.md5 | 2 +- ...st_1_1_components_1_1_i_instance_core.html | 2 +- ...repository_1_1_i_credentials_provider.html | 10 +- ...b24a1c8a29d90d03abdb627eb24635_icgraph.map | 4 +- ...b24a1c8a29d90d03abdb627eb24635_icgraph.md5 | 2 +- ...dfc1a59c4a3f30bc795c43b3c6fa42_icgraph.map | 2 +- ...dfc1a59c4a3f30bc795c43b3c6fa42_icgraph.md5 | 2 +- ..._1_repository_1_1_i_lib_git2_commands.html | 4 +- ...60f1ded05e762c347ffc43c6d71700_icgraph.map | 2 +- ...60f1ded05e762c347ffc43c6d71700_icgraph.md5 | 2 +- ...ory_1_1_i_lib_git2_repository_factory.html | 4 +- ...6ed81450e50013e2ec1bae65e5f8cb_icgraph.map | 2 +- ...6ed81450e50013e2ec1bae65e5f8cb_icgraph.md5 | 2 +- ...a092f96f2408453c2a1b5d5b0a4f30_icgraph.map | 2 +- ...a092f96f2408453c2a1b5d5b0a4f30_icgraph.md5 | 2 +- ...1_repository_1_1_i_repository-members.html | 4 +- ...nents_1_1_repository_1_1_i_repository.html | 65 +- ...e15b3dd9fe05cabc167ad5e6b3cdcd_icgraph.map | 7 +- ...e15b3dd9fe05cabc167ad5e6b3cdcd_icgraph.md5 | 2 +- ...e15b3dd9fe05cabc167ad5e6b3cdcd_icgraph.png | Bin 22663 -> 30211 bytes ...47fd2dbfe8a1f51ea38ca78259eabd_icgraph.md5 | 1 - ...47fd2dbfe8a1f51ea38ca78259eabd_icgraph.png | Bin 13564 -> 0 bytes ...a99bf9d0bc659cc3989ba4318cdfcc_icgraph.map | 5 +- ...a99bf9d0bc659cc3989ba4318cdfcc_icgraph.md5 | 1 + ...a99bf9d0bc659cc3989ba4318cdfcc_icgraph.png | Bin 0 -> 20730 bytes ...a5d05808bd1a5314dc619c6c2a6428_icgraph.map | 4 + ...a5d05808bd1a5314dc619c6c2a6428_icgraph.md5 | 1 + ...a5d05808bd1a5314dc619c6c2a6428_icgraph.png | Bin 0 -> 11212 bytes ...tory_1_1_i_repository_manager-members.html | 2 +- ...1_repository_1_1_i_repository_manager.html | 24 +- ...642bc09ffdcb87116758727bcbd813_icgraph.md5 | 1 - ...06fb30c8098ae3520612c13fcbac0c_icgraph.map | 2 +- ...06fb30c8098ae3520612c13fcbac0c_icgraph.md5 | 1 + ...06fb30c8098ae3520612c13fcbac0c_icgraph.png | Bin ...58009c7d92a55634a7ddd80ca60b1b_icgraph.map | 2 +- ...58009c7d92a55634a7ddd80ca60b1b_icgraph.md5 | 2 +- ...sion_1_1_i_session_controller-members.html | 2 +- ..._1_1_session_1_1_i_session_controller.html | 6 +- ...tabase_1_1_i_database_context_factory.html | 2 +- ..._1_host_1_1_i_o_1_1_i_file_downloader.html | 2 +- ...327aceb0182d4678f593c3385131de_icgraph.map | 2 +- ...327aceb0182d4678f593c3385131de_icgraph.md5 | 2 +- ...er_1_1_host_1_1_i_o_1_1_i_i_o_manager.html | 66 +- ...a442b5dff16f5e7a730ec354e81d78_icgraph.map | 8 +- ...a442b5dff16f5e7a730ec354e81d78_icgraph.md5 | 2 +- ...6f4eb5c679683b7e519847a6c3574e_icgraph.map | 6 +- ...6f4eb5c679683b7e519847a6c3574e_icgraph.md5 | 2 +- ...aa1b9dbeb6af3744e568095c4376e7_icgraph.map | 6 +- ...aa1b9dbeb6af3744e568095c4376e7_icgraph.md5 | 2 +- ...eb8b83ea3f4b13a183b6ac55b35a70_icgraph.map | 6 +- ...eb8b83ea3f4b13a183b6ac55b35a70_icgraph.md5 | 2 +- ...e0dda4b7fbad4c77f48ba3b2681dc7_icgraph.map | 8 +- ...e0dda4b7fbad4c77f48ba3b2681dc7_icgraph.md5 | 2 +- ...e08438da658a3c0afddbb7960e4faa_icgraph.map | 2 +- ...e08438da658a3c0afddbb7960e4faa_icgraph.md5 | 2 +- ...host_1_1_i_o_1_1_i_post_write_handler.html | 4 +- ...host_1_1_system_1_1_i_process-members.html | 2 +- ...ver_1_1_host_1_1_system_1_1_i_process.html | 6 +- ...1_1_system_1_1_i_process_base-members.html | 2 +- ..._1_host_1_1_system_1_1_i_process_base.html | 14 +- ...ost_1_1_system_1_1_i_process_features.html | 8 +- search/all_1.js | 242 +-- search/all_10.js | 345 ++- search/all_12.js | 113 +- search/all_13.js | 265 +-- search/all_14.js | 114 +- search/all_15.js | 109 +- search/all_2.js | 59 +- search/all_3.js | 341 +-- search/all_4.js | 461 ++-- search/all_6.js | 81 +- search/all_7.js | 10 +- search/all_8.js | 43 +- search/all_9.js | 749 +++---- search/all_a.js | 24 +- search/all_c.js | 8 +- search/all_d.js | 2 +- search/all_e.js | 4 +- search/all_f.js | 127 +- search/functions_0.js | 2 +- search/functions_11.js | 2 +- search/functions_13.js | 2 +- search/functions_14.js | 2 +- search/functions_2.js | 6 +- search/functions_3.js | 18 +- search/functions_5.js | 2 +- search/functions_6.js | 2 +- search/functions_7.js | 2 +- search/functions_8.js | 2 +- search/functions_9.js | 2 +- search/properties_c.js | 2 +- search/variables_12.js | 111 +- search/variables_14.js | 4 +- search/variables_2.js | 4 +- search/variables_8.js | 27 +- search/variables_f.js | 5 +- 513 files changed, 9526 insertions(+), 8745 deletions(-) rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_byond_installer_base_a6bd81dbdb1f24aaf80bba10224b4773f_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_byond_installer_base_adf1546f8ef11d749bc75509ce63bdae5_cgraph.map (100%) rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_byond_installer_base_a6bd81dbdb1f24aaf80bba10224b4773f_cgraph.md5 => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_byond_installer_base_adf1546f8ef11d749bc75509ce63bdae5_cgraph.md5 (100%) rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_byond_installer_base_a6bd81dbdb1f24aaf80bba10224b4773f_cgraph.png => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_byond_installer_base_adf1546f8ef11d749bc75509ce63bdae5_cgraph.png (100%) delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a0303d46d250191f69bb5251c89ca301d_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a0303d46d250191f69bb5251c89ca301d_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a0303d46d250191f69bb5251c89ca301d_icgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a3d2a758adff2c72db49e822c8f6ceccf_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a3d2a758adff2c72db49e822c8f6ceccf_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a3d2a758adff2c72db49e822c8f6ceccf_icgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a3d2a758adff2c72db49e822c8f6ceccf_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a4d0593064aa1c11835cfa1ab2823ec34_cgraph.map (69%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a4d0593064aa1c11835cfa1ab2823ec34_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a4d0593064aa1c11835cfa1ab2823ec34_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a3d2a758adff2c72db49e822c8f6ceccf_icgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a4d0593064aa1c11835cfa1ab2823ec34_icgraph.map (85%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a4d0593064aa1c11835cfa1ab2823ec34_icgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a3d2a758adff2c72db49e822c8f6ceccf_icgraph.png => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a4d0593064aa1c11835cfa1ab2823ec34_icgraph.png (100%) rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ad2cedaccbf100b9dcf3922a9443f8f19_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_aa9978534a863e31d7d58e51c86b5886c_cgraph.map (64%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_aa9978534a863e31d7d58e51c86b5886c_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_aa9978534a863e31d7d58e51c86b5886c_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a0303d46d250191f69bb5251c89ca301d_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ac06e9789785574f8d657a29fdd183795_cgraph.map (53%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ac06e9789785574f8d657a29fdd183795_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ac06e9789785574f8d657a29fdd183795_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a0303d46d250191f69bb5251c89ca301d_icgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ac06e9789785574f8d657a29fdd183795_icgraph.map (77%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ac06e9789785574f8d657a29fdd183795_icgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_a0303d46d250191f69bb5251c89ca301d_icgraph.png => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ac06e9789785574f8d657a29fdd183795_icgraph.png (100%) delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ad2cedaccbf100b9dcf3922a9443f8f19_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_engine_manager_ad2cedaccbf100b9dcf3922a9443f8f19_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_open_dream_installer_a6df90470a5fd85e870cf0d959181e7d8_cgraph.map delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_open_dream_installer_a6df90470a5fd85e870cf0d959181e7d8_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_open_dream_installer_a6df90470a5fd85e870cf0d959181e7d8_cgraph.png create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_open_dream_installer_a80f999e3876ac5a4c9c92684df68ec12_cgraph.map create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_open_dream_installer_a80f999e3876ac5a4c9c92684df68ec12_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_open_dream_installer_a80f999e3876ac5a4c9c92684df68ec12_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_aaa21ca98ea484845f3a7094fcc782814_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a244a180597fe2bde35fd85e43d0dd59d_cgraph.map (56%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a244a180597fe2bde35fd85e43d0dd59d_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a244a180597fe2bde35fd85e43d0dd59d_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a328bfe68ce247974125194b074003c1b_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a328bfe68ce247974125194b074003c1b_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a328bfe68ce247974125194b074003c1b_icgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a632cb5984c52022a23716cbabb1e4a40_cgraph.map create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a632cb5984c52022a23716cbabb1e4a40_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a632cb5984c52022a23716cbabb1e4a40_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a328bfe68ce247974125194b074003c1b_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a7fefc02e22b5c22787b498a045107740_cgraph.map (54%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a7fefc02e22b5c22787b498a045107740_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a7fefc02e22b5c22787b498a045107740_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a328bfe68ce247974125194b074003c1b_icgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a7fefc02e22b5c22787b498a045107740_icgraph.map (89%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a7fefc02e22b5c22787b498a045107740_icgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a328bfe68ce247974125194b074003c1b_icgraph.png => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a7fefc02e22b5c22787b498a045107740_icgraph.png (100%) delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a95068b3afe9edb4dc3a0474422f650aa_cgraph.map delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a95068b3afe9edb4dc3a0474422f650aa_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_a95068b3afe9edb4dc3a0474422f650aa_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_aa52e74ecb862a3cb6c26b89970ccc402_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_aa52e74ecb862a3cb6c26b89970ccc402_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_aaa21ca98ea484845f3a7094fcc782814_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_aaa21ca98ea484845f3a7094fcc782814_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_ad23395c46c6ba3e61646128d392d586b_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_ad23395c46c6ba3e61646128d392d586b_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_ad23395c46c6ba3e61646128d392d586b_icgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af63b639a5a6a59e780677f9849122b1f_cgraph.map create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af63b639a5a6a59e780677f9849122b1f_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af63b639a5a6a59e780677f9849122b1f_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_ad23395c46c6ba3e61646128d392d586b_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af97958179867ac2592eebd95711cf822_cgraph.map (54%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af97958179867ac2592eebd95711cf822_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af97958179867ac2592eebd95711cf822_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_ad23395c46c6ba3e61646128d392d586b_icgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af97958179867ac2592eebd95711cf822_icgraph.map (76%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af97958179867ac2592eebd95711cf822_icgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_ad23395c46c6ba3e61646128d392d586b_icgraph.png => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_af97958179867ac2592eebd95711cf822_icgraph.png (100%) rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_aa52e74ecb862a3cb6c26b89970ccc402_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_afee48c4e5681a5003e8b626bfbbc2ef8_cgraph.map (64%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_afee48c4e5681a5003e8b626bfbbc2ef8_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_afee48c4e5681a5003e8b626bfbbc2ef8_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_manager_a07aa1886c83c4ddb306ad33074f3a365_cgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_manager_a07aa1886c83c4ddb306ad33074f3a365_cgraph.png rename class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_manager_a07aa1886c83c4ddb306ad33074f3a365_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_manager_aad9235dfb77b745164af1553b922573d_cgraph.map (76%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_manager_aad9235dfb77b745164af1553b922573d_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_repository_manager_aad9235dfb77b745164af1553b922573d_cgraph.png delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_a15e986ebc3ee757beadd72f98f99076c_icgraph.md5 delete mode 100644 class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_a819e6ba4a3ccca999a74240886628b41_cgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_a15e986ebc3ee757beadd72f98f99076c_icgraph.map => class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_ad2b564fc1ab3f6caf84958bc85d5236a_icgraph.map (78%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_ad2b564fc1ab3f6caf84958bc85d5236a_icgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_a15e986ebc3ee757beadd72f98f99076c_icgraph.png => class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_ad2b564fc1ab3f6caf84958bc85d5236a_icgraph.png (100%) rename class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_a819e6ba4a3ccca999a74240886628b41_cgraph.map => class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_aee0e1a7712aa907faf658940322b8478_cgraph.map (83%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_aee0e1a7712aa907faf658940322b8478_cgraph.md5 rename class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_a819e6ba4a3ccca999a74240886628b41_cgraph.png => class_tgstation_1_1_server_1_1_host_1_1_extensions_1_1_fetch_options_extensions_aee0e1a7712aa907faf658940322b8478_cgraph.png (100%) create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter__inherit__graph.map create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter__inherit__graph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter__inherit__graph.png create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter_a3e9230c68a7eff4ddf044bb8c07836cc_cgraph.map create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter_a3e9230c68a7eff4ddf044bb8c07836cc_cgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter_a3e9230c68a7eff4ddf044bb8c07836cc_cgraph.png create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter_aa95af832a3c5781b796441234fc0e5fe_icgraph.map create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter_aa95af832a3c5781b796441234fc0e5fe_icgraph.md5 create mode 100644 class_tgstation_1_1_server_1_1_host_1_1_jobs_1_1_job_progress_reporter_aa95af832a3c5781b796441234fc0e5fe_icgraph.png delete mode 100644 inherit_graph_199.map delete mode 100644 inherit_graph_199.md5 delete mode 100644 inherit_graph_199.png rename interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_i_engine_installer_a76100637a7abd23c97157b7a4deb4736_icgraph.map => interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_i_engine_installer_a1841dfb27438fbd4d70462cd137bcb42_icgraph.map (72%) create mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_i_engine_installer_a1841dfb27438fbd4d70462cd137bcb42_icgraph.md5 rename interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_i_engine_installer_a76100637a7abd23c97157b7a4deb4736_icgraph.png => interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_i_engine_installer_a1841dfb27438fbd4d70462cd137bcb42_icgraph.png (100%) delete mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_engine_1_1_i_engine_installer_a76100637a7abd23c97157b7a4deb4736_icgraph.md5 delete mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_abd47fd2dbfe8a1f51ea38ca78259eabd_icgraph.md5 delete mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_abd47fd2dbfe8a1f51ea38ca78259eabd_icgraph.png rename interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_abd47fd2dbfe8a1f51ea38ca78259eabd_icgraph.map => interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_ac1a99bf9d0bc659cc3989ba4318cdfcc_icgraph.map (55%) create mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_ac1a99bf9d0bc659cc3989ba4318cdfcc_icgraph.md5 create mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_ac1a99bf9d0bc659cc3989ba4318cdfcc_icgraph.png create mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_adea5d05808bd1a5314dc619c6c2a6428_icgraph.map create mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_adea5d05808bd1a5314dc619c6c2a6428_icgraph.md5 create mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_adea5d05808bd1a5314dc619c6c2a6428_icgraph.png delete mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_manager_a01642bc09ffdcb87116758727bcbd813_icgraph.md5 rename interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_manager_a01642bc09ffdcb87116758727bcbd813_icgraph.map => interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_manager_a0506fb30c8098ae3520612c13fcbac0c_icgraph.map (89%) create mode 100644 interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_manager_a0506fb30c8098ae3520612c13fcbac0c_icgraph.md5 rename interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_manager_a01642bc09ffdcb87116758727bcbd813_icgraph.png => interface_tgstation_1_1_server_1_1_host_1_1_components_1_1_repository_1_1_i_repository_manager_a0506fb30c8098ae3520612c13fcbac0c_icgraph.png (100%) diff --git a/_byond_installer_base_8cs_source.html b/_byond_installer_base_8cs_source.html index 6a8237f825..3535685bb3 100644 --- a/_byond_installer_base_8cs_source.html +++ b/_byond_installer_base_8cs_source.html @@ -188,7 +188,7 @@ $(function() {
145 }
146 }
147
-
149 public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
+
149 public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken)
150 {
151 CheckVersionValidity(version);
152
@@ -239,11 +239,11 @@ $(function() {
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.ByondBinPath
const string ByondBinPath
The path to the BYOND bin folder.
Definition: ByondInstallerBase.cs:24
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.AdditionalCacheCleanFilePaths
virtual IEnumerable< string > AdditionalCacheCleanFilePaths(string configDirectory)
List off additional file paths in the configDirectory to delete.
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.DreamMakerName
abstract string DreamMakerName
Path to the DreamMaker executable.
Definition: ByondInstallerBase.cs:52
-
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.DownloadVersion
override async ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Definition: ByondInstallerBase.cs:149
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.ByondInstallerBase
ByondInstallerBase(IIOManager ioManager, ILogger< ByondInstallerBase > logger, IFileDownloader fileDownloader)
Initializes a new instance of the ByondInstallerBase class.
Definition: ByondInstallerBase.cs:70
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.CleanCache
override async Task CleanCache(CancellationToken cancellationToken)
Attempts to cleans the engine's cache folder for the system. A Task representing the running operatio...
Definition: ByondInstallerBase.cs:103
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.GetDownloadZipUrl
Uri GetDownloadZipUrl(EngineVersion version)
Create a Uri pointing to the location of the download for a given version .
Definition: ByondInstallerBase.cs:194
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.TargetEngineType
override EngineType TargetEngineType
Definition: ByondInstallerBase.cs:42
+
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.DownloadVersion
override async ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Definition: ByondInstallerBase.cs:149
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.GetDreamDaemonName
abstract string GetDreamDaemonName(Version byondVersion, out bool supportsCli)
Get the file name of the DreamDaemon executable.
Tgstation.Server.Host.Components.Engine.ByondInstallerBase.CreateInstallation
override IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
Creates an IEngineInstallation for a given version . The IEngineInstallation.
Definition: ByondInstallerBase.cs:77
Tgstation.Server.Host.Components.Engine.EngineInstallerBase
Definition: EngineInstallerBase.cs:15
@@ -253,7 +253,7 @@ $(function() {
Tgstation.Server.Host.Components.Engine.ZipStreamEngineInstallationData
Implementation of IEngineInstallationData for a zip file in a Stream.
Definition: ZipStreamEngineInstallationData.cs:14
Tgstation.Server.Host.IO.BufferedFileStreamProvider
IFileStreamProvider that provides a ISeekableFileStreamProvider from an input Stream.
Definition: BufferedFileStreamProvider.cs:14
Tgstation.Server.Host.IO.ResolvingIOManager
An IIOManager that resolve relative paths from another IIOManager to a subdirectory of that.
Definition: ResolvingIOManager.cs:10
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Components.Engine.IEngineInstallation
Represents a BYOND installation.
Definition: IEngineInstallation.cs:18
Tgstation.Server.Host.IO.IFileDownloader
Downloads files.
Definition: IFileDownloader.cs:9
Tgstation.Server.Host.IO.IFileDownloader.DownloadFile
IFileStreamProvider DownloadFile(Uri url, string? bearerToken)
Downloads a file from a given url .
diff --git a/_delegating_engine_installer_8cs_source.html b/_delegating_engine_installer_8cs_source.html index 8ae4555dbd..7e2c2ea539 100644 --- a/_delegating_engine_installer_8cs_source.html +++ b/_delegating_engine_installer_8cs_source.html @@ -103,7 +103,7 @@ $(function() {
36 public IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
37 => DelegateCall(version, installer => installer.CreateInstallation(version, path, installationTask));
38
-
40 public ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
+
40 public ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
41 => DelegateCall(version, installer => installer.DownloadVersion(version, jobProgressReporter, cancellationToken));
42
44 public ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
@@ -127,14 +127,14 @@ $(function() {
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller
Implementation of IEngineInstaller that forwards calls to different IEngineInstaller based on their a...
Definition: DelegatingEngineInstaller.cs:16
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.CreateInstallation
IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
Creates an IEngineInstallation for a given version . The IEngineInstallation.
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.DelegatingEngineInstaller
DelegatingEngineInstaller(FrozenDictionary< EngineType, IEngineInstaller > delegatedInstallers)
Initializes a new instance of the DelegatingEngineInstaller class.
Definition: DelegatingEngineInstaller.cs:26
-
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.DownloadVersion
ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.DelegateCall< TReturn >
TReturn DelegateCall< TReturn >(EngineVersion version, Func< IEngineInstaller, TReturn > call)
Delegate a given call to its appropriate IEngineInstaller.
Definition: DelegatingEngineInstaller.cs:62
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.Install
ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Does actions necessary to get an extracted installation working. A ValueTask representing the running...
+
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.DownloadVersion
ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.UpgradeInstallation
ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
Does actions necessary to get upgrade a version installed by a previous version of TGS....
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.CleanCache
Task CleanCache(CancellationToken cancellationToken)
Attempts to cleans the engine's cache folder for the system. A Task representing the running operatio...
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.delegatedInstallers
readonly FrozenDictionary< EngineType, IEngineInstaller > delegatedInstallers
The FrozenDictionary<TKey, TValue> mapping EngineTypes to their appropriate IEngineInstaller.
Definition: DelegatingEngineInstaller.cs:20
Tgstation.Server.Host.Components.Engine.DelegatingEngineInstaller.TrustDmbPath
ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken)
Add a given fullDmbPath to the trusted DMBs list in BYOND's config. A ValueTask representing the run...
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Components.Engine.IEngineInstallation
Represents a BYOND installation.
Definition: IEngineInstallation.cs:18
Tgstation.Server.Host.Components.Engine.IEngineInstaller
For downloading and installing game engines for a given system.
Definition: IEngineInstaller.cs:13
Tgstation.Server.Api.Models
Definition: ChatChannel.cs:6
diff --git a/_dream_maker_8cs_source.html b/_dream_maker_8cs_source.html index e0c965bb59..a9bcbc294a 100644 --- a/_dream_maker_8cs_source.html +++ b/_dream_maker_8cs_source.html @@ -972,8 +972,8 @@ $(function() {
Tgstation.Server.Host.Components.Repository.Repository.Repository
Repository(LibGit2Sharp.IRepository libGitRepo, ILibGit2Commands commands, IIOManager ioManager, IEventConsumer eventConsumer, ICredentialsProvider credentialsProvider, IPostWriteHandler postWriteHandler, IGitRemoteFeaturesFactory gitRemoteFeaturesFactory, ILibGit2RepositoryFactory submoduleFactory, ILogger< Repository > logger, GeneralConfiguration generalConfiguration, Action disposeAction)
Initializes a new instance of the Repository class.
Definition: Repository.cs:144
Tgstation.Server.Host.Configuration.SessionConfiguration
Configuration options for the game sessions.
Definition: SessionConfiguration.cs:7
Tgstation.Server.Host.Jobs.JobException
Operation exceptions thrown from the context of a Models.Job.
Definition: JobException.cs:11
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:74
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:137
Tgstation.Server.Host.Models.Instance
Represents an Api.Models.Instance in the database.
Definition: Instance.cs:11
Tgstation.Server.Host.Models.RevisionInformation
Definition: RevisionInformation.cs:10
Tgstation.Server.Host.Models.RevisionInformation.Id
long Id
The row Id.
Definition: RevisionInformation.cs:14
diff --git a/_engine_controller_8cs_source.html b/_engine_controller_8cs_source.html index f370eb96e8..d1132e1a83 100644 --- a/_engine_controller_8cs_source.html +++ b/_engine_controller_8cs_source.html @@ -217,175 +217,176 @@ $(function() {
184
185 try
186 {
-
187 await byondManager.ChangeVersion(null, model.EngineVersion, null, false, cancellationToken);
-
188 }
-
189 catch (InvalidOperationException ex)
-
190 {
-
191 Logger.LogDebug(
-
192 ex,
-
193 "Race condition: Engine {version} uninstalled before we could switch to it. Creating install job instead...",
-
194 model);
-
195 versionAlreadyInstalled = false;
-
196 }
-
197 }
-
198
-
199 if (!versionAlreadyInstalled)
-
200 {
-
201 if (model.EngineVersion.CustomIteration.HasValue)
-
202 return BadRequest(new ErrorMessageResponse(ErrorCode.EngineNonExistentCustomVersion));
-
203
-
204 Logger.LogInformation(
-
205 "User ID {userId} installing engine version {newByondVersion} on instance ID {instanceId}",
-
206 AuthenticationContext.User.Id,
-
207 model,
-
208 Instance.Id);
-
209
-
210 // run the install through the job manager
-
211 var job = Models.Job.Create(
-
212 uploadingZip
-
213 ? JobCode.EngineCustomInstall
-
214 : JobCode.EngineOfficialInstall,
-
215 AuthenticationContext.User,
-
216 Instance,
-
217 EngineRights.CancelInstall);
-
218 job.Description += $" {model.EngineVersion}";
-
219
-
220 IFileUploadTicket? fileUploadTicket = null;
-
221 if (uploadingZip)
-
222 fileUploadTicket = fileTransferService.CreateUpload(FileUploadStreamKind.None);
-
223
-
224 try
-
225 {
-
226 await jobManager.RegisterOperation(
-
227 job,
-
228 async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) =>
-
229 {
-
230 MemoryStream? zipFileStream = null;
-
231 if (fileUploadTicket != null)
-
232 await using (fileUploadTicket)
-
233 {
-
234 var uploadStream = await fileUploadTicket.GetResult(jobCancellationToken) ?? throw new JobException(ErrorCode.FileUploadExpired);
-
235 zipFileStream = new MemoryStream();
-
236 try
-
237 {
-
238 await uploadStream.CopyToAsync(zipFileStream, jobCancellationToken);
-
239 }
-
240 catch
-
241 {
-
242 await zipFileStream.DisposeAsync();
-
243 throw;
-
244 }
-
245 }
-
246
-
247 await using (zipFileStream)
-
248 await core!.EngineManager.ChangeVersion(
-
249 progressHandler,
-
250 model.EngineVersion,
-
251 zipFileStream,
-
252 true,
-
253 jobCancellationToken);
-
254 },
-
255 cancellationToken);
-
256
-
257 result.InstallJob = job.ToApi();
-
258 result.FileTicket = fileUploadTicket?.Ticket.FileTicket;
-
259 }
-
260 catch
-
261 {
-
262 if (fileUploadTicket != null)
-
263 await fileUploadTicket.DisposeAsync();
-
264
-
265 throw;
-
266 }
-
267 }
-
268
-
269 return result.InstallJob != null ? Accepted(result) : Json(result);
-
270 });
-
271 }
-
272
-
282 [HttpDelete]
-
283 [TgsAuthorize(EngineRights.DeleteInstall)]
-
284 [ProducesResponseType(typeof(JobResponse), 202)]
-
285 [ProducesResponseType(typeof(ErrorMessageResponse), 409)]
-
286 [ProducesResponseType(typeof(ErrorMessageResponse), 410)]
-
287 public async ValueTask<IActionResult> Delete([FromBody] EngineVersionDeleteRequest model, CancellationToken cancellationToken)
-
288 {
-
289 ArgumentNullException.ThrowIfNull(model);
-
290 var earlyOut = ValidateEngineVersion(model.EngineVersion);
-
291 if (earlyOut != null)
-
292 return earlyOut;
-
293
-
294 var engineVersion = model.EngineVersion!;
-
295 var notInstalledResponse = await WithComponentInstanceNullable(
-
296 instance =>
-
297 {
-
298 var byondManager = instance.EngineManager;
-
299 var activeVersion = byondManager.ActiveVersion;
-
300 if (activeVersion != null && engineVersion.Equals(activeVersion))
-
301 return ValueTask.FromResult<IActionResult?>(
-
302 Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion)));
-
303
-
304 var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(engineVersion));
-
305
-
306 return ValueTask.FromResult<IActionResult?>(
-
307 versionNotInstalled
-
308 ? this.Gone()
-
309 : null);
-
310 });
-
311
-
312 if (notInstalledResponse != null)
-
313 return notInstalledResponse;
-
314
-
315 var isByondVersion = engineVersion.Engine!.Value == EngineType.Byond;
-
316
-
317 // run the install through the job manager
-
318 var cancelRight = isByondVersion
-
319 ? engineVersion.CustomIteration.HasValue
-
320 ? EngineRights.InstallCustomByondVersion
-
321 : EngineRights.InstallOfficialOrChangeActiveByondVersion
-
322 : engineVersion.CustomIteration.HasValue
-
323 ? EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion
-
324 : EngineRights.InstallCustomOpenDreamVersion;
-
325
-
326 var job = Models.Job.Create(JobCode.EngineDelete, AuthenticationContext.User, Instance, cancelRight);
-
327 job.Description += $" {engineVersion}";
-
328
-
329 await jobManager.RegisterOperation(
-
330 job,
-
331 (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken)
-
332 => instanceCore!.EngineManager.DeleteVersion(progressReporter, engineVersion, jobCancellationToken),
-
333 cancellationToken);
-
334
-
335 var apiResponse = job.ToApi();
-
336 return Accepted(apiResponse);
-
337 }
-
338
-
344 BadRequestObjectResult? ValidateEngineVersion(EngineVersion? version)
-
345 {
-
346 if (version == null || !version.Engine.HasValue)
-
347 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
-
348
-
349 var isByond = version.Engine.Value == EngineType.Byond;
-
350 var validSha = version.SourceSHA?.Length == Limits.MaximumCommitShaLength;
-
351 if ((isByond
-
352 && (version.Version == null
-
353 || validSha))
-
354 || (version.Engine.Value == EngineType.OpenDream &&
-
355 ((version.SourceSHA == null && version.Version == null)
-
356 || (version.Version != null && (version.Version.Revision != -1 || validSha)))))
-
357 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
-
358
-
359 if (isByond)
-
360 {
-
361 version.Version = NormalizeByondVersion(version.Version!);
-
362 if (version.Version.Build != -1)
-
363 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
-
364 }
-
365
-
366 return null;
-
367 }
-
368 }
-
369}
+
187 using var progressReporter = new JobProgressReporter();
+
188 await byondManager.ChangeVersion(progressReporter, model.EngineVersion, null, false, cancellationToken);
+
189 }
+
190 catch (InvalidOperationException ex)
+
191 {
+
192 Logger.LogDebug(
+
193 ex,
+
194 "Race condition: Engine {version} uninstalled before we could switch to it. Creating install job instead...",
+
195 model);
+
196 versionAlreadyInstalled = false;
+
197 }
+
198 }
+
199
+
200 if (!versionAlreadyInstalled)
+
201 {
+
202 if (model.EngineVersion.CustomIteration.HasValue)
+
203 return BadRequest(new ErrorMessageResponse(ErrorCode.EngineNonExistentCustomVersion));
+
204
+
205 Logger.LogInformation(
+
206 "User ID {userId} installing engine version {newByondVersion} on instance ID {instanceId}",
+
207 AuthenticationContext.User.Id,
+
208 model,
+
209 Instance.Id);
+
210
+
211 // run the install through the job manager
+
212 var job = Models.Job.Create(
+
213 uploadingZip
+
214 ? JobCode.EngineCustomInstall
+
215 : JobCode.EngineOfficialInstall,
+
216 AuthenticationContext.User,
+
217 Instance,
+
218 EngineRights.CancelInstall);
+
219 job.Description += $" {model.EngineVersion}";
+
220
+
221 IFileUploadTicket? fileUploadTicket = null;
+
222 if (uploadingZip)
+
223 fileUploadTicket = fileTransferService.CreateUpload(FileUploadStreamKind.None);
+
224
+
225 try
+
226 {
+
227 await jobManager.RegisterOperation(
+
228 job,
+
229 async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) =>
+
230 {
+
231 MemoryStream? zipFileStream = null;
+
232 if (fileUploadTicket != null)
+
233 await using (fileUploadTicket)
+
234 {
+
235 var uploadStream = await fileUploadTicket.GetResult(jobCancellationToken) ?? throw new JobException(ErrorCode.FileUploadExpired);
+
236 zipFileStream = new MemoryStream();
+
237 try
+
238 {
+
239 await uploadStream.CopyToAsync(zipFileStream, jobCancellationToken);
+
240 }
+
241 catch
+
242 {
+
243 await zipFileStream.DisposeAsync();
+
244 throw;
+
245 }
+
246 }
+
247
+
248 await using (zipFileStream)
+
249 await core!.EngineManager.ChangeVersion(
+
250 progressHandler,
+
251 model.EngineVersion,
+
252 zipFileStream,
+
253 true,
+
254 jobCancellationToken);
+
255 },
+
256 cancellationToken);
+
257
+
258 result.InstallJob = job.ToApi();
+
259 result.FileTicket = fileUploadTicket?.Ticket.FileTicket;
+
260 }
+
261 catch
+
262 {
+
263 if (fileUploadTicket != null)
+
264 await fileUploadTicket.DisposeAsync();
+
265
+
266 throw;
+
267 }
+
268 }
+
269
+
270 return result.InstallJob != null ? Accepted(result) : Json(result);
+
271 });
+
272 }
+
273
+
283 [HttpDelete]
+
284 [TgsAuthorize(EngineRights.DeleteInstall)]
+
285 [ProducesResponseType(typeof(JobResponse), 202)]
+
286 [ProducesResponseType(typeof(ErrorMessageResponse), 409)]
+
287 [ProducesResponseType(typeof(ErrorMessageResponse), 410)]
+
288 public async ValueTask<IActionResult> Delete([FromBody] EngineVersionDeleteRequest model, CancellationToken cancellationToken)
+
289 {
+
290 ArgumentNullException.ThrowIfNull(model);
+
291 var earlyOut = ValidateEngineVersion(model.EngineVersion);
+
292 if (earlyOut != null)
+
293 return earlyOut;
+
294
+
295 var engineVersion = model.EngineVersion!;
+
296 var notInstalledResponse = await WithComponentInstanceNullable(
+
297 instance =>
+
298 {
+
299 var byondManager = instance.EngineManager;
+
300 var activeVersion = byondManager.ActiveVersion;
+
301 if (activeVersion != null && engineVersion.Equals(activeVersion))
+
302 return ValueTask.FromResult<IActionResult?>(
+
303 Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion)));
+
304
+
305 var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(engineVersion));
+
306
+
307 return ValueTask.FromResult<IActionResult?>(
+
308 versionNotInstalled
+
309 ? this.Gone()
+
310 : null);
+
311 });
+
312
+
313 if (notInstalledResponse != null)
+
314 return notInstalledResponse;
+
315
+
316 var isByondVersion = engineVersion.Engine!.Value == EngineType.Byond;
+
317
+
318 // run the install through the job manager
+
319 var cancelRight = isByondVersion
+
320 ? engineVersion.CustomIteration.HasValue
+
321 ? EngineRights.InstallCustomByondVersion
+
322 : EngineRights.InstallOfficialOrChangeActiveByondVersion
+
323 : engineVersion.CustomIteration.HasValue
+
324 ? EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion
+
325 : EngineRights.InstallCustomOpenDreamVersion;
+
326
+
327 var job = Models.Job.Create(JobCode.EngineDelete, AuthenticationContext.User, Instance, cancelRight);
+
328 job.Description += $" {engineVersion}";
+
329
+
330 await jobManager.RegisterOperation(
+
331 job,
+
332 (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken)
+
333 => instanceCore!.EngineManager.DeleteVersion(progressReporter, engineVersion, jobCancellationToken),
+
334 cancellationToken);
+
335
+
336 var apiResponse = job.ToApi();
+
337 return Accepted(apiResponse);
+
338 }
+
339
+
345 BadRequestObjectResult? ValidateEngineVersion(EngineVersion? version)
+
346 {
+
347 if (version == null || !version.Engine.HasValue)
+
348 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
+
349
+
350 var isByond = version.Engine.Value == EngineType.Byond;
+
351 var validSha = version.SourceSHA?.Length == Limits.MaximumCommitShaLength;
+
352 if ((isByond
+
353 && (version.Version == null
+
354 || validSha))
+
355 || (version.Engine.Value == EngineType.OpenDream &&
+
356 ((version.SourceSHA == null && version.Version == null)
+
357 || (version.Version != null && (version.Version.Revision != -1 || validSha)))))
+
358 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
+
359
+
360 if (isByond)
+
361 {
+
362 version.Version = NormalizeByondVersion(version.Version!);
+
363 if (version.Version.Build != -1)
+
364 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
+
365 }
+
366
+
367 return null;
+
368 }
+
369 }
+
370}
Tgstation.Server.Api.Models.EngineVersion
Information about an engine installation.
Definition: EngineVersion.cs:14
Tgstation.Server.Api.Models.EngineVersion.Version
Version? Version
The System.Version of the engine. Currently only valid when Engine is EngineType.Byond.
Definition: EngineVersion.cs:30
Tgstation.Server.Api.Models.EngineVersion.SourceSHA
string? SourceSHA
The git commit SHA of the engine. Currently only valid when Engine is EngineType.OpenDream.
Definition: EngineVersion.cs:37
@@ -415,8 +416,8 @@ $(function() {
Tgstation.Server.Host.Controllers.EngineController.List
ValueTask< IActionResult > List([FromQuery] int? page, [FromQuery] int? pageSize, CancellationToken cancellationToken)
Lists installed EngineVersions.
Tgstation.Server.Host.Controllers.EngineController.EngineController
EngineController(IDatabaseContext databaseContext, IAuthenticationContext authenticationContext, ILogger< EngineController > logger, IInstanceManager instanceManager, IJobManager jobManager, IFileTransferTicketProvider fileTransferService, IApiHeadersProvider apiHeadersProvider)
Initializes a new instance of the EngineController class.
Definition: EngineController.cs:61
Tgstation.Server.Host.Controllers.EngineController.NormalizeByondVersion
static Version NormalizeByondVersion(Version version)
Remove the Version.Build from a given version if present.
-
Tgstation.Server.Host.Controllers.EngineController.Delete
async ValueTask< IActionResult > Delete([FromBody] EngineVersionDeleteRequest model, CancellationToken cancellationToken)
Attempts to delete the BYOND version specified in a given model from the instance.
Definition: EngineController.cs:287
-
Tgstation.Server.Host.Controllers.EngineController.ValidateEngineVersion
BadRequestObjectResult? ValidateEngineVersion(EngineVersion? version)
Validate and normalize a given version .
Definition: EngineController.cs:344
+
Tgstation.Server.Host.Controllers.EngineController.Delete
async ValueTask< IActionResult > Delete([FromBody] EngineVersionDeleteRequest model, CancellationToken cancellationToken)
Attempts to delete the BYOND version specified in a given model from the instance.
Definition: EngineController.cs:288
+
Tgstation.Server.Host.Controllers.EngineController.ValidateEngineVersion
BadRequestObjectResult? ValidateEngineVersion(EngineVersion? version)
Validate and normalize a given version .
Definition: EngineController.cs:345
Tgstation.Server.Host.Controllers.EngineController.Update
async ValueTask< IActionResult > Update([FromBody] EngineVersionRequest model, CancellationToken cancellationToken)
Changes the active engine version to the one specified in a given model .
Definition: EngineController.cs:147
Tgstation.Server.Host.Controllers.EngineController.jobManager
readonly IJobManager jobManager
The IJobManager for the EngineController.
Definition: EngineController.cs:37
Tgstation.Server.Host.Controllers.InstanceRequiredController
ComponentInterfacingController for operations that require an instance.
Definition: InstanceRequiredController.cs:14
diff --git a/_engine_installer_base_8cs_source.html b/_engine_installer_base_8cs_source.html index 5b851aa1c1..d2864ea51a 100644 --- a/_engine_installer_base_8cs_source.html +++ b/_engine_installer_base_8cs_source.html @@ -111,7 +111,7 @@ $(function() {
50
52 public abstract ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken);
53
-
55 public abstract ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken);
+
55 public abstract ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken);
56
58 public abstract ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken);
59
@@ -127,17 +127,17 @@ $(function() {
Tgstation.Server.Api.Models.EngineVersion.Engine
EngineType? Engine
The EngineType.
Definition: EngineVersion.cs:24
Tgstation.Server.Host.Components.Engine.EngineInstallerBase
Definition: EngineInstallerBase.cs:15
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.TrustDmbPath
abstract ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken)
Add a given fullDmbPath to the trusted DMBs list in BYOND's config. A ValueTask representing the run...
-
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.DownloadVersion
abstract ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.CleanCache
abstract Task CleanCache(CancellationToken cancellationToken)
Attempts to cleans the engine's cache folder for the system. A Task representing the running operatio...
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.CheckVersionValidity
void CheckVersionValidity(EngineVersion version)
Check that a given version is of type EngineType.Byond.
Definition: EngineInstallerBase.cs:64
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.CreateInstallation
abstract IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
Creates an IEngineInstallation for a given version . The IEngineInstallation.
+
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.DownloadVersion
abstract ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.IOManager
IIOManager IOManager
Gets the IIOManager for the EngineInstallerBase.
Definition: EngineInstallerBase.cs:24
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.EngineInstallerBase
EngineInstallerBase(IIOManager ioManager, ILogger< EngineInstallerBase > logger)
Initializes a new instance of the EngineInstallerBase class.
Definition: EngineInstallerBase.cs:36
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.Install
abstract ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Does actions necessary to get an extracted installation working. A ValueTask representing the running...
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.Logger
ILogger< EngineInstallerBase > Logger
Gets the ILogger for the EngineInstallerBase.
Definition: EngineInstallerBase.cs:29
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.TargetEngineType
abstract EngineType TargetEngineType
The EngineType the installer supports.
Definition: EngineInstallerBase.cs:19
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.UpgradeInstallation
abstract ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
Does actions necessary to get upgrade a version installed by a previous version of TGS....
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Components.Engine.IEngineInstallation
Represents a BYOND installation.
Definition: IEngineInstallation.cs:18
Tgstation.Server.Host.Components.Engine.IEngineInstaller
For downloading and installing game engines for a given system.
Definition: IEngineInstaller.cs:13
Tgstation.Server.Host.IO.IIOManager
Interface for using filesystems.
Definition: IIOManager.cs:13
diff --git a/_engine_manager_8cs_source.html b/_engine_manager_8cs_source.html index 1fe1bed93b..103dbfb3a0 100644 --- a/_engine_manager_8cs_source.html +++ b/_engine_manager_8cs_source.html @@ -153,8 +153,8 @@ $(function() {
115
117 public void Dispose() => changeDeleteSemaphore.Dispose();
118
-
120 public async ValueTask ChangeVersion(
-
121 JobProgressReporter? progressReporter,
+
120 public async ValueTask ChangeVersion(
+
121 JobProgressReporter progressReporter,
122 EngineVersion version,
123 Stream? customVersionStream,
124 bool allowInstallation,
@@ -164,7 +164,7 @@ $(function() {
128
129 using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken))
130 {
-
131 using var installLock = await AssertAndLockVersion(
+
131 using var installLock = await AssertAndLockVersion(
132 progressReporter,
133 version,
134 customVersionStream,
@@ -201,419 +201,430 @@ $(function() {
166 "Acquiring lock on BYOND version {version}...",
167 requiredVersion?.ToString() ?? $"{ActiveVersion} (active)");
168 var versionToUse = requiredVersion ?? ActiveVersion ?? throw new JobException(ErrorCode.EngineNoVersionsInstalled);
-
169 var installLock = await AssertAndLockVersion(
-
170 null,
-
171 versionToUse,
-
172 null,
-
173 requiredVersion != null,
-
174 true,
-
175 cancellationToken);
-
176 try
-
177 {
-
178 if (trustDmbFullPath != null)
-
179 await engineInstaller.TrustDmbPath(installLock.Version, trustDmbFullPath, cancellationToken);
-
180
-
181 return installLock;
-
182 }
-
183 catch
-
184 {
-
185 installLock.Dispose();
-
186 throw;
-
187 }
-
188 }
-
189
-
191 public async ValueTask DeleteVersion(JobProgressReporter progressReporter, EngineVersion version, CancellationToken cancellationToken)
-
192 {
-
193 ArgumentNullException.ThrowIfNull(progressReporter);
-
194
-
195 CheckVersionParameter(version);
-
196
-
197 logger.LogTrace("DeleteVersion {version}", version);
-
198
-
199 var activeVersion = ActiveVersion;
-
200 if (activeVersion != null && version.Equals(activeVersion))
-
201 throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion);
-
202
-
203 ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> container;
-
204 logger.LogTrace("Waiting to acquire installedVersions lock...");
-
205 lock (installedVersions)
-
206 {
-
207 if (!installedVersions.TryGetValue(version, out var containerNullable))
-
208 {
-
209 logger.LogTrace("Version {version} already deleted.", version);
-
210 return;
-
211 }
-
212
-
213 container = containerNullable;
-
214 logger.LogTrace("Installation container acquired for deletion");
-
215 }
-
216
-
217 progressReporter.StageName = "Waiting for version to not be in use...";
-
218 while (true)
-
219 {
-
220 var containerTask = container.OnZeroReferences;
-
221
-
222 // We also want to check when the active version changes in case we need to fail the job because of that.
-
223 Task activeVersionUpdate;
-
224 using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken))
-
225 activeVersionUpdate = activeVersionChanged.Task;
-
226
-
227 logger.LogTrace("Waiting for container.OnZeroReferences or switch of active version...");
-
228 await Task.WhenAny(
-
229 containerTask,
-
230 activeVersionUpdate)
-
231 .WaitAsync(cancellationToken);
-
232
-
233 if (containerTask.IsCompleted)
-
234 logger.LogTrace("All locks for version {version} are gone", version);
-
235 else
-
236 logger.LogTrace("activeVersion changed, we may have to wait again. Acquiring semaphore...");
-
237
-
238 using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken))
-
239 {
-
240 // check again because it could have become the active version.
-
241 activeVersion = ActiveVersion;
-
242 if (activeVersion != null && version.Equals(activeVersion))
-
243 throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion);
-
244
-
245 bool proceed;
-
246 logger.LogTrace("Locking installedVersions...");
-
247 lock (installedVersions)
-
248 {
-
249 proceed = container.OnZeroReferences.IsCompleted;
-
250 if (proceed)
-
251 if (!installedVersions.TryGetValue(version, out var newerContainer))
-
252 logger.LogWarning("Unable to remove engine installation {version} from list! Is there a duplicate job running?", version);
-
253 else
-
254 {
-
255 if (container != newerContainer)
-
256 {
-
257 // Okay let me get this straight, there was a duplicate delete job, it ran before us after we grabbed the container, AND another installation of the same version completed?
-
258 // I know realistically this is practically impossible, but god damn that small possiblility
-
259 // best thing to do is check we exclusively own the newer container
-
260 logger.LogDebug("Extreme race condition encountered, applying concentrated copium...");
-
261 container = newerContainer;
-
262 proceed = container.OnZeroReferences.IsCompleted;
-
263 }
-
264
-
265 if (proceed)
-
266 {
-
267 logger.LogTrace("Proceeding with installation deletion...");
-
268 installedVersions.Remove(version);
-
269 }
-
270 }
-
271 }
-
272
-
273 if (proceed)
-
274 {
-
275 logger.LogInformation("Deleting version {version}...", version);
-
276 progressReporter.StageName = "Deleting installation...";
-
277
-
278 // delete the version file first, because we will know not to re-discover the installation if it's not present and it will get cleaned on reboot
-
279 var installPath = version.ToString();
-
280 await ioManager.DeleteFile(
-
281 ioManager.ConcatPath(installPath, VersionFileName),
-
282 cancellationToken);
-
283 await ioManager.DeleteDirectory(installPath, cancellationToken);
-
284 return;
-
285 }
-
286
-
287 if (containerTask.IsCompleted)
-
288 logger.LogDebug(
-
289 "Another lock was acquired before we could remove version {version} from the list. We will have to wait again.",
-
290 version);
-
291 else
-
292 logger.LogTrace("Not proceeding for some reason or another");
-
293 }
-
294 }
-
295 }
-
296
-
298 public async Task StartAsync(CancellationToken cancellationToken)
-
299 {
-
300 async ValueTask<byte[]?> GetActiveVersion()
-
301 {
-
302 var activeVersionFileExists = await ioManager.FileExists(ActiveVersionFileName, cancellationToken);
-
303 return !activeVersionFileExists ? null : await ioManager.ReadAllBytes(ActiveVersionFileName, cancellationToken);
-
304 }
-
305
-
306 var activeVersionBytesTask = GetActiveVersion();
-
307
-
308 await ioManager.CreateDirectory(DefaultIOManager.CurrentDirectory, cancellationToken);
-
309 var directories = await ioManager.GetDirectories(DefaultIOManager.CurrentDirectory, cancellationToken);
+
169
+
170 using var progressReporter = new JobProgressReporter();
+
171
+
172 var installLock = await AssertAndLockVersion(
+
173 progressReporter,
+
174 versionToUse,
+
175 null,
+
176 requiredVersion != null,
+
177 true,
+
178 cancellationToken);
+
179 try
+
180 {
+
181 if (trustDmbFullPath != null)
+
182 await engineInstaller.TrustDmbPath(installLock.Version, trustDmbFullPath, cancellationToken);
+
183
+
184 return installLock;
+
185 }
+
186 catch
+
187 {
+
188 installLock.Dispose();
+
189 throw;
+
190 }
+
191 }
+
192
+
194 public async ValueTask DeleteVersion(JobProgressReporter progressReporter, EngineVersion version, CancellationToken cancellationToken)
+
195 {
+
196 ArgumentNullException.ThrowIfNull(progressReporter);
+
197
+
198 CheckVersionParameter(version);
+
199
+
200 logger.LogTrace("DeleteVersion {version}", version);
+
201
+
202 var activeVersion = ActiveVersion;
+
203 if (activeVersion != null && version.Equals(activeVersion))
+
204 throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion);
+
205
+
206 ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> container;
+
207 logger.LogTrace("Waiting to acquire installedVersions lock...");
+
208 lock (installedVersions)
+
209 {
+
210 if (!installedVersions.TryGetValue(version, out var containerNullable))
+
211 {
+
212 logger.LogTrace("Version {version} already deleted.", version);
+
213 return;
+
214 }
+
215
+
216 container = containerNullable;
+
217 logger.LogTrace("Installation container acquired for deletion");
+
218 }
+
219
+
220 progressReporter.StageName = "Waiting for version to not be in use...";
+
221 while (true)
+
222 {
+
223 var containerTask = container.OnZeroReferences;
+
224
+
225 // We also want to check when the active version changes in case we need to fail the job because of that.
+
226 Task activeVersionUpdate;
+
227 using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken))
+
228 activeVersionUpdate = activeVersionChanged.Task;
+
229
+
230 logger.LogTrace("Waiting for container.OnZeroReferences or switch of active version...");
+
231 await Task.WhenAny(
+
232 containerTask,
+
233 activeVersionUpdate)
+
234 .WaitAsync(cancellationToken);
+
235
+
236 if (containerTask.IsCompleted)
+
237 logger.LogTrace("All locks for version {version} are gone", version);
+
238 else
+
239 logger.LogTrace("activeVersion changed, we may have to wait again. Acquiring semaphore...");
+
240
+
241 using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken))
+
242 {
+
243 // check again because it could have become the active version.
+
244 activeVersion = ActiveVersion;
+
245 if (activeVersion != null && version.Equals(activeVersion))
+
246 throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion);
+
247
+
248 bool proceed;
+
249 logger.LogTrace("Locking installedVersions...");
+
250 lock (installedVersions)
+
251 {
+
252 proceed = container.OnZeroReferences.IsCompleted;
+
253 if (proceed)
+
254 if (!installedVersions.TryGetValue(version, out var newerContainer))
+
255 logger.LogWarning("Unable to remove engine installation {version} from list! Is there a duplicate job running?", version);
+
256 else
+
257 {
+
258 if (container != newerContainer)
+
259 {
+
260 // Okay let me get this straight, there was a duplicate delete job, it ran before us after we grabbed the container, AND another installation of the same version completed?
+
261 // I know realistically this is practically impossible, but god damn that small possiblility
+
262 // best thing to do is check we exclusively own the newer container
+
263 logger.LogDebug("Extreme race condition encountered, applying concentrated copium...");
+
264 container = newerContainer;
+
265 proceed = container.OnZeroReferences.IsCompleted;
+
266 }
+
267
+
268 if (proceed)
+
269 {
+
270 logger.LogTrace("Proceeding with installation deletion...");
+
271 installedVersions.Remove(version);
+
272 }
+
273 }
+
274 }
+
275
+
276 if (proceed)
+
277 {
+
278 logger.LogInformation("Deleting version {version}...", version);
+
279 progressReporter.StageName = "Deleting installation...";
+
280
+
281 // delete the version file first, because we will know not to re-discover the installation if it's not present and it will get cleaned on reboot
+
282 var installPath = version.ToString();
+
283 await ioManager.DeleteFile(
+
284 ioManager.ConcatPath(installPath, VersionFileName),
+
285 cancellationToken);
+
286 await ioManager.DeleteDirectory(installPath, cancellationToken);
+
287 return;
+
288 }
+
289
+
290 if (containerTask.IsCompleted)
+
291 logger.LogDebug(
+
292 "Another lock was acquired before we could remove version {version} from the list. We will have to wait again.",
+
293 version);
+
294 else
+
295 logger.LogTrace("Not proceeding for some reason or another");
+
296 }
+
297 }
+
298 }
+
299
+
301 public async Task StartAsync(CancellationToken cancellationToken)
+
302 {
+
303 async ValueTask<byte[]?> GetActiveVersion()
+
304 {
+
305 var activeVersionFileExists = await ioManager.FileExists(ActiveVersionFileName, cancellationToken);
+
306 return !activeVersionFileExists ? null : await ioManager.ReadAllBytes(ActiveVersionFileName, cancellationToken);
+
307 }
+
308
+
309 var activeVersionBytesTask = GetActiveVersion();
310
-
311 var installedVersionPaths = new Dictionary<string, EngineVersion>();
-
312
-
313 async ValueTask ReadVersion(string path)
-
314 {
-
315 var versionFile = ioManager.ConcatPath(path, VersionFileName);
-
316 if (!await ioManager.FileExists(versionFile, cancellationToken))
-
317 {
-
318 logger.LogWarning("Cleaning path with no version file: {versionPath}", ioManager.ResolvePath(path));
-
319 await ioManager.DeleteDirectory(path, cancellationToken); // cleanup
-
320 return;
-
321 }
-
322
-
323 var bytes = await ioManager.ReadAllBytes(versionFile, cancellationToken);
-
324 var text = Encoding.UTF8.GetString(bytes);
-
325 EngineVersion version;
-
326 if (!EngineVersion.TryParse(text, out var versionNullable))
-
327 {
-
328 logger.LogWarning("Cleaning path with unparsable version file: {versionPath}", ioManager.ResolvePath(path));
-
329 await ioManager.DeleteDirectory(path, cancellationToken); // cleanup
-
330 return;
-
331 }
-
332 else
-
333 version = versionNullable!;
-
334
-
335 try
-
336 {
-
337 AddInstallationContainer(version, path, Task.CompletedTask);
-
338 logger.LogDebug("Added detected BYOND version {versionKey}...", version);
-
339 }
-
340 catch (Exception ex)
-
341 {
-
342 logger.LogWarning(
-
343 ex,
-
344 "It seems that there are multiple directories that say they contain BYOND version {version}. We're ignoring and cleaning the duplicate: {duplicatePath}",
-
345 version,
-
346 ioManager.ResolvePath(path));
-
347 await ioManager.DeleteDirectory(path, cancellationToken);
-
348 return;
-
349 }
-
350
-
351 lock (installedVersionPaths)
-
352 installedVersionPaths.Add(ioManager.ResolvePath(version.ToString()), version);
-
353 }
-
354
-
355 await ValueTaskExtensions.WhenAll(
-
356 directories
-
357 .Select(ReadVersion));
-
358
-
359 logger.LogTrace("Upgrading BYOND installations...");
-
360 await ValueTaskExtensions.WhenAll(
-
361 installedVersionPaths
-
362 .Select(kvp => engineInstaller.UpgradeInstallation(kvp.Value, kvp.Key, cancellationToken)));
-
363
-
364 var activeVersionBytes = await activeVersionBytesTask;
-
365 if (activeVersionBytes != null)
-
366 {
-
367 var activeVersionString = Encoding.UTF8.GetString(activeVersionBytes);
-
368
-
369 EngineVersion? activeVersion;
-
370 bool hasRequestedActiveVersion;
-
371 lock (installedVersions)
-
372 hasRequestedActiveVersion = EngineVersion.TryParse(activeVersionString, out activeVersion)
-
373 && installedVersions.ContainsKey(activeVersion!);
-
374
-
375 if (hasRequestedActiveVersion)
-
376 ActiveVersion = activeVersion; // not setting TCS because there's no need during init
-
377 else
-
378 {
-
379 logger.LogWarning("Failed to load saved active version {activeVersion}!", activeVersionString);
-
380 await ioManager.DeleteFile(ActiveVersionFileName, cancellationToken);
-
381 }
-
382 }
-
383 }
-
384
-
386 public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+
311 await ioManager.CreateDirectory(DefaultIOManager.CurrentDirectory, cancellationToken);
+
312 var directories = await ioManager.GetDirectories(DefaultIOManager.CurrentDirectory, cancellationToken);
+
313
+
314 var installedVersionPaths = new Dictionary<string, EngineVersion>();
+
315
+
316 async ValueTask ReadVersion(string path)
+
317 {
+
318 var versionFile = ioManager.ConcatPath(path, VersionFileName);
+
319 if (!await ioManager.FileExists(versionFile, cancellationToken))
+
320 {
+
321 logger.LogWarning("Cleaning path with no version file: {versionPath}", ioManager.ResolvePath(path));
+
322 await ioManager.DeleteDirectory(path, cancellationToken); // cleanup
+
323 return;
+
324 }
+
325
+
326 var bytes = await ioManager.ReadAllBytes(versionFile, cancellationToken);
+
327 var text = Encoding.UTF8.GetString(bytes);
+
328 EngineVersion version;
+
329 if (!EngineVersion.TryParse(text, out var versionNullable))
+
330 {
+
331 logger.LogWarning("Cleaning path with unparsable version file: {versionPath}", ioManager.ResolvePath(path));
+
332 await ioManager.DeleteDirectory(path, cancellationToken); // cleanup
+
333 return;
+
334 }
+
335 else
+
336 version = versionNullable!;
+
337
+
338 try
+
339 {
+
340 AddInstallationContainer(version, path, Task.CompletedTask);
+
341 logger.LogDebug("Added detected BYOND version {versionKey}...", version);
+
342 }
+
343 catch (Exception ex)
+
344 {
+
345 logger.LogWarning(
+
346 ex,
+
347 "It seems that there are multiple directories that say they contain BYOND version {version}. We're ignoring and cleaning the duplicate: {duplicatePath}",
+
348 version,
+
349 ioManager.ResolvePath(path));
+
350 await ioManager.DeleteDirectory(path, cancellationToken);
+
351 return;
+
352 }
+
353
+
354 lock (installedVersionPaths)
+
355 installedVersionPaths.Add(ioManager.ResolvePath(version.ToString()), version);
+
356 }
+
357
+
358 await ValueTaskExtensions.WhenAll(
+
359 directories
+
360 .Select(ReadVersion));
+
361
+
362 logger.LogTrace("Upgrading BYOND installations...");
+
363 await ValueTaskExtensions.WhenAll(
+
364 installedVersionPaths
+
365 .Select(kvp => engineInstaller.UpgradeInstallation(kvp.Value, kvp.Key, cancellationToken)));
+
366
+
367 var activeVersionBytes = await activeVersionBytesTask;
+
368 if (activeVersionBytes != null)
+
369 {
+
370 var activeVersionString = Encoding.UTF8.GetString(activeVersionBytes);
+
371
+
372 EngineVersion? activeVersion;
+
373 bool hasRequestedActiveVersion;
+
374 lock (installedVersions)
+
375 hasRequestedActiveVersion = EngineVersion.TryParse(activeVersionString, out activeVersion)
+
376 && installedVersions.ContainsKey(activeVersion!);
+
377
+
378 if (hasRequestedActiveVersion)
+
379 ActiveVersion = activeVersion; // not setting TCS because there's no need during init
+
380 else
+
381 {
+
382 logger.LogWarning("Failed to load saved active version {activeVersion}!", activeVersionString);
+
383 await ioManager.DeleteFile(ActiveVersionFileName, cancellationToken);
+
384 }
+
385 }
+
386 }
387
-
398 async ValueTask<EngineExecutableLock> AssertAndLockVersion(
-
399 JobProgressReporter? progressReporter,
-
400 EngineVersion version,
-
401 Stream? customVersionStream,
-
402 bool neededForLock,
-
403 bool allowInstallation,
-
404 CancellationToken cancellationToken)
-
405 {
-
406 var ourTcs = new TaskCompletionSource();
-
407 IEngineInstallation installation;
-
408 EngineExecutableLock installLock;
-
409 bool installedOrInstalling;
-
410 lock (installedVersions)
-
411 {
-
412 if (customVersionStream != null)
-
413 {
-
414 var customInstallationNumber = 1;
-
415 do
-
416 {
-
417 version.CustomIteration = customInstallationNumber++;
-
418 }
-
419 while (installedVersions.ContainsKey(version));
-
420 }
-
421
-
422 installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainerNullable);
-
423 ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> installationContainer;
-
424 if (!installedOrInstalling)
-
425 {
-
426 if (!allowInstallation)
-
427 throw new InvalidOperationException($"Engine version {version} not installed!");
-
428
-
429 installationContainer = AddInstallationContainer(
-
430 version,
-
431 ioManager.ResolvePath(version.ToString()),
-
432 ourTcs.Task);
-
433 }
-
434 else
-
435 installationContainer = installationContainerNullable!;
-
436
-
437 installation = installationContainer.Instance;
-
438 installLock = installationContainer.AddReference();
-
439 }
-
440
-
441 var deploymentPipelineProcesses = !neededForLock;
-
442 try
-
443 {
-
444 if (installedOrInstalling)
-
445 {
-
446 if (progressReporter != null)
-
447 progressReporter.StageName = "Waiting for existing installation job...";
-
448
-
449 if (neededForLock && !installation.InstallationTask.IsCompleted)
-
450 logger.LogWarning("The required engine version ({version}) is not readily available! We will have to wait for it to install.", version);
-
451
-
452 await installation.InstallationTask.WaitAsync(cancellationToken);
-
453 return installLock;
-
454 }
-
455
-
456 // okay up to us to install it then
-
457 try
-
458 {
-
459 if (customVersionStream != null)
-
460 logger.LogInformation("Installing custom engine version as {version}...", version);
-
461 else if (neededForLock)
-
462 {
-
463 if (version.CustomIteration.HasValue)
-
464 throw new JobException(ErrorCode.EngineNonExistentCustomVersion);
-
465
-
466 logger.LogWarning("The required engine version ({version}) is not readily available! We will have to install it.", version);
-
467 }
-
468 else
-
469 logger.LogInformation("Requested engine version {version} not currently installed. Doing so now...", version);
-
470
-
471 if (progressReporter != null)
-
472 progressReporter.StageName = "Running event";
-
473
-
474 var versionString = version.ToString();
-
475 await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
-
476
-
477 await InstallVersionFiles(progressReporter, version, customVersionStream, deploymentPipelineProcesses, cancellationToken);
-
478
-
479 ourTcs.SetResult();
-
480
-
481 await eventConsumer.HandleEvent(EventType.EngineInstallComplete, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
-
482 }
-
483 catch (Exception ex)
-
484 {
-
485 if (ex is not OperationCanceledException)
-
486 await eventConsumer.HandleEvent(EventType.EngineInstallFail, new List<string> { ex.Message }, deploymentPipelineProcesses, cancellationToken);
-
487
-
488 lock (installedVersions)
-
489 installedVersions.Remove(version);
-
490
-
491 ourTcs.SetException(ex);
-
492 throw;
-
493 }
-
494
-
495 return installLock;
-
496 }
-
497 catch
-
498 {
-
499 installLock.Dispose();
-
500 throw;
-
501 }
-
502 }
-
503
-
513 async ValueTask InstallVersionFiles(
-
514 JobProgressReporter? progressReporter,
-
515 EngineVersion version,
-
516 Stream? customVersionStream,
-
517 bool deploymentPipelineProcesses,
-
518 CancellationToken cancellationToken)
-
519 {
-
520 var installFullPath = ioManager.ResolvePath(version.ToString());
-
521 async ValueTask DirectoryCleanup()
-
522 {
-
523 await ioManager.DeleteDirectory(installFullPath, cancellationToken);
-
524 await ioManager.CreateDirectory(installFullPath, cancellationToken);
-
525 }
-
526
-
527 var directoryCleanupTask = DirectoryCleanup();
-
528 try
-
529 {
-
530 IEngineInstallationData engineInstallationData;
-
531 if (customVersionStream == null)
-
532 {
-
533 if (progressReporter != null)
-
534 progressReporter.StageName = "Downloading version";
-
535
-
536 engineInstallationData = await engineInstaller.DownloadVersion(version, progressReporter, cancellationToken);
-
537
-
538 progressReporter?.ReportProgress(null);
-
539 }
-
540 else
-
541#pragma warning disable CA2000 // Dispose objects before losing scope, false positive
-
542 engineInstallationData = new ZipStreamEngineInstallationData(
-
543 ioManager,
-
544 customVersionStream);
-
545#pragma warning restore CA2000 // Dispose objects before losing scope
-
546
-
547 await using (engineInstallationData)
+
389 public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+
390
+
401 async ValueTask<EngineExecutableLock> AssertAndLockVersion(
+
402 JobProgressReporter progressReporter,
+
403 EngineVersion version,
+
404 Stream? customVersionStream,
+
405 bool neededForLock,
+
406 bool allowInstallation,
+
407 CancellationToken cancellationToken)
+
408 {
+
409 var ourTcs = new TaskCompletionSource();
+
410 IEngineInstallation installation;
+
411 EngineExecutableLock installLock;
+
412 bool installedOrInstalling;
+
413 lock (installedVersions)
+
414 {
+
415 if (customVersionStream != null)
+
416 {
+
417 var customInstallationNumber = 1;
+
418 do
+
419 {
+
420 version.CustomIteration = customInstallationNumber++;
+
421 }
+
422 while (installedVersions.ContainsKey(version));
+
423 }
+
424
+
425 installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainerNullable);
+
426 ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> installationContainer;
+
427 if (!installedOrInstalling)
+
428 {
+
429 if (!allowInstallation)
+
430 throw new InvalidOperationException($"Engine version {version} not installed!");
+
431
+
432 installationContainer = AddInstallationContainer(
+
433 version,
+
434 ioManager.ResolvePath(version.ToString()),
+
435 ourTcs.Task);
+
436 }
+
437 else
+
438 installationContainer = installationContainerNullable!;
+
439
+
440 installation = installationContainer.Instance;
+
441 installLock = installationContainer.AddReference();
+
442 }
+
443
+
444 var deploymentPipelineProcesses = !neededForLock;
+
445 try
+
446 {
+
447 if (installedOrInstalling)
+
448 {
+
449 progressReporter.StageName = "Waiting for existing installation job...";
+
450
+
451 if (neededForLock && !installation.InstallationTask.IsCompleted)
+
452 logger.LogWarning("The required engine version ({version}) is not readily available! We will have to wait for it to install.", version);
+
453
+
454 await installation.InstallationTask.WaitAsync(cancellationToken);
+
455 return installLock;
+
456 }
+
457
+
458 // okay up to us to install it then
+
459 try
+
460 {
+
461 if (customVersionStream != null)
+
462 logger.LogInformation("Installing custom engine version as {version}...", version);
+
463 else if (neededForLock)
+
464 {
+
465 if (version.CustomIteration.HasValue)
+
466 throw new JobException(ErrorCode.EngineNonExistentCustomVersion);
+
467
+
468 logger.LogWarning("The required engine version ({version}) is not readily available! We will have to install it.", version);
+
469 }
+
470 else
+
471 logger.LogInformation("Requested engine version {version} not currently installed. Doing so now...", version);
+
472
+
473 progressReporter.StageName = "Running event";
+
474
+
475 var versionString = version.ToString();
+
476 await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
+
477
+
478 await InstallVersionFiles(progressReporter, version, customVersionStream, deploymentPipelineProcesses, cancellationToken);
+
479
+
480 ourTcs.SetResult();
+
481
+
482 await eventConsumer.HandleEvent(EventType.EngineInstallComplete, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
+
483 }
+
484 catch (Exception ex)
+
485 {
+
486 if (ex is not OperationCanceledException)
+
487 await eventConsumer.HandleEvent(EventType.EngineInstallFail, new List<string> { ex.Message }, deploymentPipelineProcesses, cancellationToken);
+
488
+
489 lock (installedVersions)
+
490 installedVersions.Remove(version);
+
491
+
492 ourTcs.SetException(ex);
+
493 throw;
+
494 }
+
495
+
496 return installLock;
+
497 }
+
498 catch
+
499 {
+
500 installLock.Dispose();
+
501 throw;
+
502 }
+
503 }
+
504
+
514 async ValueTask InstallVersionFiles(
+
515 JobProgressReporter progressReporter,
+
516 EngineVersion version,
+
517 Stream? customVersionStream,
+
518 bool deploymentPipelineProcesses,
+
519 CancellationToken cancellationToken)
+
520 {
+
521 var installFullPath = ioManager.ResolvePath(version.ToString());
+
522 async ValueTask DirectoryCleanup()
+
523 {
+
524 await ioManager.DeleteDirectory(installFullPath, cancellationToken);
+
525 await ioManager.CreateDirectory(installFullPath, cancellationToken);
+
526 }
+
527
+
528 var directoryCleanupTask = DirectoryCleanup();
+
529 try
+
530 {
+
531 IEngineInstallationData engineInstallationData;
+
532 var remainingProgress = 1.0;
+
533 if (customVersionStream == null)
+
534 {
+
535 using var subReporter = progressReporter.CreateSection("Downloading Version", 0.5);
+
536 remainingProgress -= 0.5;
+
537 engineInstallationData = await engineInstaller.DownloadVersion(version, subReporter, cancellationToken);
+
538 }
+
539 else
+
540#pragma warning disable CA2000 // Dispose objects before losing scope, false positive
+
541 engineInstallationData = new ZipStreamEngineInstallationData(
+
542 ioManager,
+
543 customVersionStream);
+
544#pragma warning restore CA2000 // Dispose objects before losing scope
+
545
+
546 JobProgressReporter remainingReporter;
+
547 try
548 {
-
549 if (progressReporter != null)
-
550 progressReporter.StageName = "Cleaning target directory";
-
551
-
552 await directoryCleanupTask;
-
553
-
554 if (progressReporter != null)
-
555 progressReporter.StageName = "Extracting data";
+
549 remainingReporter = progressReporter.CreateSection(null, remainingProgress);
+
550 }
+
551 catch
+
552 {
+
553 await engineInstallationData.DisposeAsync();
+
554 throw;
+
555 }
556
-
557 logger.LogTrace("Extracting engine to {extractPath}...", installFullPath);
-
558 await engineInstallationData.ExtractToPath(installFullPath, cancellationToken);
-
559 }
-
560
-
561 if (progressReporter != null)
-
562 progressReporter.StageName = "Running installation actions";
-
563
-
564 await engineInstaller.Install(version, installFullPath, deploymentPipelineProcesses, cancellationToken);
-
565
-
566 if (progressReporter != null)
-
567 progressReporter.StageName = "Writing version file";
-
568
-
569 // make sure to do this last because this is what tells us we have a valid version in the future
-
570 await ioManager.WriteAllBytes(
-
571 ioManager.ConcatPath(installFullPath, VersionFileName),
-
572 Encoding.UTF8.GetBytes(version.ToString()),
-
573 cancellationToken);
-
574 }
-
575 catch (HttpRequestException ex)
-
576 {
-
577 // since the user can easily provide non-exitent version numbers, we'll turn this into a JobException
-
578 throw new JobException(ErrorCode.EngineDownloadFail, ex);
-
579 }
-
580 catch (OperationCanceledException)
-
581 {
-
582 throw;
-
583 }
-
584 catch
-
585 {
-
586 await ioManager.DeleteDirectory(installFullPath, cancellationToken);
-
587 throw;
-
588 }
-
589 }
-
590
-
598 ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> AddInstallationContainer(EngineVersion version, string installPath, Task installationTask)
-
599 {
-
600 var installation = engineInstaller.CreateInstallation(version, installPath, installationTask);
+
557 using (remainingReporter)
+
558 {
+
559 await using (engineInstallationData)
+
560 {
+
561 remainingReporter.StageName = "Cleaning target directory";
+
562
+
563 await directoryCleanupTask;
+
564 remainingReporter.ReportProgress(0.1);
+
565 remainingReporter.StageName = "Extracting data";
+
566
+
567 logger.LogTrace("Extracting engine to {extractPath}...", installFullPath);
+
568 await engineInstallationData.ExtractToPath(installFullPath, cancellationToken);
+
569 remainingReporter.ReportProgress(0.3);
+
570 }
+
571
+
572 remainingReporter.StageName = "Running installation actions";
+
573
+
574 await engineInstaller.Install(version, installFullPath, deploymentPipelineProcesses, cancellationToken);
+
575
+
576 remainingReporter.ReportProgress(0.9);
+
577 remainingReporter.StageName = "Writing version file";
+
578
+
579 // make sure to do this last because this is what tells us we have a valid version in the future
+
580 await ioManager.WriteAllBytes(
+
581 ioManager.ConcatPath(installFullPath, VersionFileName),
+
582 Encoding.UTF8.GetBytes(version.ToString()),
+
583 cancellationToken);
+
584 }
+
585 }
+
586 catch (HttpRequestException ex)
+
587 {
+
588 // since the user can easily provide non-exitent version numbers, we'll turn this into a JobException
+
589 throw new JobException(ErrorCode.EngineDownloadFail, ex);
+
590 }
+
591 catch (OperationCanceledException)
+
592 {
+
593 throw;
+
594 }
+
595 catch
+
596 {
+
597 await ioManager.DeleteDirectory(installFullPath, cancellationToken);
+
598 throw;
+
599 }
+
600 }
601
-
602 var installationContainer = new ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock>(installation);
-
603
-
604 lock (installedVersions)
-
605 installedVersions.Add(version, installationContainer);
-
606
-
607 return installationContainer;
-
608 }
-
609 }
-
610}
+
609 ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> AddInstallationContainer(EngineVersion version, string installPath, Task installationTask)
+
610 {
+
611 var installation = engineInstaller.CreateInstallation(version, installPath, installationTask);
+
612
+
613 var installationContainer = new ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock>(installation);
+
614
+
615 lock (installedVersions)
+
616 installedVersions.Add(version, installationContainer);
+
617
+
618 return installationContainer;
+
619 }
+
620 }
+
621}
Exception
Stream
Tgstation.Server.Api.Models.EngineVersion
Information about an engine installation.
Definition: EngineVersion.cs:14
@@ -626,34 +637,35 @@ $(function() {
Tgstation.Server.Common.Extensions.ValueTaskExtensions.WhenAll
static async ValueTask WhenAll(IEnumerable< ValueTask > tasks)
Fully await a given list of tasks .
Definition: ValueTaskExtensions.cs:99
Tgstation.Server.Host.Components.Engine.EngineExecutableLock
Definition: EngineExecutableLock.cs:17
Tgstation.Server.Host.Components.Engine.EngineManager
Definition: EngineManager.cs:23
-
Tgstation.Server.Host.Components.Engine.EngineManager.InstallVersionFiles
async ValueTask InstallVersionFiles(JobProgressReporter? progressReporter, EngineVersion version, Stream? customVersionStream, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Installs the files for a given BYOND version .
Definition: EngineManager.cs:513
Tgstation.Server.Host.Components.Engine.EngineManager.CheckVersionParameter
static void CheckVersionParameter(EngineVersion version)
Validates a given version parameter.
Definition: EngineManager.cs:86
Tgstation.Server.Host.Components.Engine.EngineManager.installedVersions
readonly Dictionary< EngineVersion, ReferenceCountingContainer< IEngineInstallation, EngineExecutableLock > > installedVersions
Map of byond EngineVersions to Tasks that complete when they are installed.
Definition: EngineManager.cs:70
Tgstation.Server.Host.Components.Engine.EngineManager.StopAsync
Task StopAsync(CancellationToken cancellationToken)
-
Tgstation.Server.Host.Components.Engine.EngineManager.AssertAndLockVersion
async ValueTask< EngineExecutableLock > AssertAndLockVersion(JobProgressReporter? progressReporter, EngineVersion version, Stream? customVersionStream, bool neededForLock, bool allowInstallation, CancellationToken cancellationToken)
Ensures a BYOND version is installed if it isn't already.
Definition: EngineManager.cs:398
Tgstation.Server.Host.Components.Engine.EngineManager.VersionFileName
const string VersionFileName
The file in which we store the Version for installations.
Definition: EngineManager.cs:27
-
Tgstation.Server.Host.Components.Engine.EngineManager.StartAsync
async Task StartAsync(CancellationToken cancellationToken)
Definition: EngineManager.cs:298
+
Tgstation.Server.Host.Components.Engine.EngineManager.StartAsync
async Task StartAsync(CancellationToken cancellationToken)
Definition: EngineManager.cs:301
Tgstation.Server.Host.Components.Engine.EngineManager.InstalledVersions
IReadOnlyList< EngineVersion > InstalledVersions
The installed EngineVersions.
Definition: EngineManager.cs:39
+
Tgstation.Server.Host.Components.Engine.EngineManager.AssertAndLockVersion
async ValueTask< EngineExecutableLock > AssertAndLockVersion(JobProgressReporter progressReporter, EngineVersion version, Stream? customVersionStream, bool neededForLock, bool allowInstallation, CancellationToken cancellationToken)
Ensures a BYOND version is installed if it isn't already.
Definition: EngineManager.cs:401
Tgstation.Server.Host.Components.Engine.EngineManager.activeVersionChanged
volatile TaskCompletionSource activeVersionChanged
TaskCompletionSource that notifes when the ActiveVersion changes.
Definition: EngineManager.cs:80
Tgstation.Server.Host.Components.Engine.EngineManager.ActiveVersionFileName
const string ActiveVersionFileName
The file in which we store the ActiveVersion.
Definition: EngineManager.cs:32
Tgstation.Server.Host.Components.Engine.EngineManager.UseExecutables
async ValueTask< IEngineExecutableLock > UseExecutables(EngineVersion? requiredVersion, string? trustDmbFullPath, CancellationToken cancellationToken)
Lock the current installation's location and return a IEngineExecutableLock. A ValueTask<TResult> res...
Definition: EngineManager.cs:163
-
Tgstation.Server.Host.Components.Engine.EngineManager.DeleteVersion
async ValueTask DeleteVersion(JobProgressReporter progressReporter, EngineVersion version, CancellationToken cancellationToken)
Deletes a given version from the disk. A Task representing the running operation.
Definition: EngineManager.cs:191
+
Tgstation.Server.Host.Components.Engine.EngineManager.DeleteVersion
async ValueTask DeleteVersion(JobProgressReporter progressReporter, EngineVersion version, CancellationToken cancellationToken)
Deletes a given version from the disk. A Task representing the running operation.
Definition: EngineManager.cs:194
Tgstation.Server.Host.Components.Engine.EngineManager.ActiveVersion
EngineVersion? ActiveVersion
The currently active EngineVersion.
Definition: EngineManager.cs:35
Tgstation.Server.Host.Components.Engine.EngineManager.EngineManager
EngineManager(IIOManager ioManager, IEngineInstaller engineInstaller, IEventConsumer eventConsumer, ILogger< EngineManager > logger)
Initializes a new instance of the EngineManager class.
Definition: EngineManager.cs:104
Tgstation.Server.Host.Components.Engine.EngineManager.changeDeleteSemaphore
readonly SemaphoreSlim changeDeleteSemaphore
The SemaphoreSlim for changing or deleting the active BYOND version.
Definition: EngineManager.cs:75
+
Tgstation.Server.Host.Components.Engine.EngineManager.ChangeVersion
async ValueTask ChangeVersion(JobProgressReporter progressReporter, EngineVersion version, Stream? customVersionStream, bool allowInstallation, CancellationToken cancellationToken)
Change the active EngineVersion. A ValueTask representing the running operation.
Definition: EngineManager.cs:120
Tgstation.Server.Host.Components.Engine.EngineManager.eventConsumer
readonly IEventConsumer eventConsumer
The IEventConsumer for the EngineManager.
Definition: EngineManager.cs:60
Tgstation.Server.Host.Components.Engine.EngineManager.ioManager
readonly IIOManager ioManager
The IIOManager for the EngineManager.
Definition: EngineManager.cs:50
Tgstation.Server.Host.Components.Engine.EngineManager.engineInstaller
readonly IEngineInstaller engineInstaller
The IEngineInstaller for the EngineManager.
Definition: EngineManager.cs:55
+
Tgstation.Server.Host.Components.Engine.EngineManager.InstallVersionFiles
async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, EngineVersion version, Stream? customVersionStream, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Installs the files for a given BYOND version .
Definition: EngineManager.cs:514
Tgstation.Server.Host.Components.Engine.EngineManager.logger
readonly ILogger< EngineManager > logger
The ILogger for the EngineManager.
Definition: EngineManager.cs:65
-
Tgstation.Server.Host.Components.Engine.EngineManager.AddInstallationContainer
ReferenceCountingContainer< IEngineInstallation, EngineExecutableLock > AddInstallationContainer(EngineVersion version, string installPath, Task installationTask)
Create and add a new IEngineInstallation to installedVersions.
Definition: EngineManager.cs:598
-
Tgstation.Server.Host.Components.Engine.EngineManager.ChangeVersion
async ValueTask ChangeVersion(JobProgressReporter? progressReporter, EngineVersion version, Stream? customVersionStream, bool allowInstallation, CancellationToken cancellationToken)
Change the active EngineVersion. A ValueTask representing the running operation.
Definition: EngineManager.cs:120
+
Tgstation.Server.Host.Components.Engine.EngineManager.AddInstallationContainer
ReferenceCountingContainer< IEngineInstallation, EngineExecutableLock > AddInstallationContainer(EngineVersion version, string installPath, Task installationTask)
Create and add a new IEngineInstallation to installedVersions.
Definition: EngineManager.cs:609
Tgstation.Server.Host.Components.Engine.EngineManager.Dispose
void Dispose()
Tgstation.Server.Host.Components.Engine.ZipStreamEngineInstallationData
Implementation of IEngineInstallationData for a zip file in a Stream.
Definition: ZipStreamEngineInstallationData.cs:14
Tgstation.Server.Host.IO.DefaultIOManager
IIOManager that resolves paths to Environment.CurrentDirectory.
Definition: DefaultIOManager.cs:17
Tgstation.Server.Host.IO.DefaultIOManager.CurrentDirectory
const string CurrentDirectory
Path to the current working directory for the IIOManager.
Definition: DefaultIOManager.cs:21
Tgstation.Server.Host.Jobs.JobException
Operation exceptions thrown from the context of a Models.Job.
Definition: JobException.cs:11
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:74
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:176
+
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:137
Tgstation.Server.Host.Utils.ReferenceCounter.Dispose
void Dispose()
Definition: ReferenceCounter.cs:46
Tgstation.Server.Host.Utils.ReferenceCountingContainer
Wrapper for managing some TWrapped .
Definition: ReferenceCountingContainer.cs:14
Tgstation.Server.Host.Utils.ReferenceCountingContainer.AddReference
TReference AddReference()
Create a new TReference to the Instance.
Definition: ReferenceCountingContainer.cs:66
@@ -667,8 +679,8 @@ $(function() {
Tgstation.Server.Host.Components.Engine.IEngineInstallation.InstallationTask
Task InstallationTask
The Task that completes when the BYOND version finished installing.
Definition: IEngineInstallation.cs:57
Tgstation.Server.Host.Components.Engine.IEngineInstaller
For downloading and installing game engines for a given system.
Definition: IEngineInstaller.cs:13
Tgstation.Server.Host.Components.Engine.IEngineInstaller.CreateInstallation
IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
Creates an IEngineInstallation for a given version .
+
Tgstation.Server.Host.Components.Engine.IEngineInstaller.DownloadVersion
ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version .
Tgstation.Server.Host.Components.Engine.IEngineInstaller.UpgradeInstallation
ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
Does actions necessary to get upgrade a version installed by a previous version of TGS.
-
Tgstation.Server.Host.Components.Engine.IEngineInstaller.DownloadVersion
ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version .
Tgstation.Server.Host.Components.Engine.IEngineInstaller.Install
ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Does actions necessary to get an extracted installation working.
Tgstation.Server.Host.Components.Engine.IEngineInstaller.TrustDmbPath
ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken)
Add a given fullDmbPath to the trusted DMBs list in BYOND's config.
Tgstation.Server.Host.Components.Engine.IEngineManager
For managing the engine installations.
Definition: IEngineManager.cs:17
diff --git a/_fetch_options_extensions_8cs_source.html b/_fetch_options_extensions_8cs_source.html index db74527f9a..5db8e826bb 100644 --- a/_fetch_options_extensions_8cs_source.html +++ b/_fetch_options_extensions_8cs_source.html @@ -91,10 +91,10 @@ $(function() {
12{
16 static class FetchOptionsExtensions
17 {
-
27 public static FetchOptions Hydrate(
+
27 public static FetchOptions Hydrate(
28 this FetchOptions fetchOptions,
29 ILogger logger,
-
30 JobProgressReporter? progressReporter,
+
30 JobProgressReporter progressReporter,
31 CredentialsHandler credentialsHandler,
32 CancellationToken cancellationToken)
33 {
@@ -115,7 +115,7 @@ $(function() {
48 fetchOptions.OnUpdateTips = (_, _, _) => !cancellationToken.IsCancellationRequested;
49 fetchOptions.CredentialsProvider = credentialsHandler;
50 fetchOptions.RepositoryOperationStarting = _ => !cancellationToken.IsCancellationRequested;
-
51 fetchOptions.OnTransferProgress = TransferProgressHandler(
+
51 fetchOptions.OnTransferProgress = TransferProgressHandler(
52 logger,
53 progressReporter,
54 cancellationToken);
@@ -123,7 +123,7 @@ $(function() {
56 return fetchOptions;
57 }
58
-
66 static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter? progressReporter, CancellationToken cancellationToken) => transferProgress =>
+
66 static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter progressReporter, CancellationToken cancellationToken) => transferProgress =>
67 {
68 double? percentage;
69 var totalObjectsToProcess = transferProgress.TotalObjects * 2;
@@ -150,10 +150,10 @@ $(function() {
90 }
91}
Tgstation.Server.Host.Extensions.FetchOptionsExtensions
Extension methods for FetchOptions.
Definition: FetchOptionsExtensions.cs:17
-
Tgstation.Server.Host.Extensions.FetchOptionsExtensions.TransferProgressHandler
static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
Generate a LibGit2Sharp.Handlers.TransferProgressHandler from a given progressReporter and cancellat...
-
Tgstation.Server.Host.Extensions.FetchOptionsExtensions.Hydrate
static FetchOptions Hydrate(this FetchOptions fetchOptions, ILogger logger, JobProgressReporter? progressReporter, CredentialsHandler credentialsHandler, CancellationToken cancellationToken)
Hydrate a given set of fetchOptions .
Definition: FetchOptionsExtensions.cs:27
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:74
+
Tgstation.Server.Host.Extensions.FetchOptionsExtensions.TransferProgressHandler
static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Generate a LibGit2Sharp.Handlers.TransferProgressHandler from a given progressReporter and cancellat...
+
Tgstation.Server.Host.Extensions.FetchOptionsExtensions.Hydrate
static FetchOptions Hydrate(this FetchOptions fetchOptions, ILogger logger, JobProgressReporter progressReporter, CredentialsHandler credentialsHandler, CancellationToken cancellationToken)
Hydrate a given set of fetchOptions .
Definition: FetchOptionsExtensions.cs:27
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:137
Tgstation.Server.Host.Extensions
Definition: ApplicationBuilderExtensions.cs:21
Tgstation.Server.Host.Jobs
Definition: IJobManager.cs:8
diff --git a/_i_dream_maker_8cs_source.html b/_i_dream_maker_8cs_source.html index 7fb1a47af6..434ad3496a 100644 --- a/_i_dream_maker_8cs_source.html +++ b/_i_dream_maker_8cs_source.html @@ -95,7 +95,7 @@ $(function() {
27 CancellationToken cancellationToken);
28 }
29}
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Models.Job
Definition: Job.cs:16
Tgstation.Server.Host.Components.Deployment.IDreamMaker
For managing the compiler.
Definition: IDreamMaker.cs:14
Tgstation.Server.Host.Components.Deployment.IDreamMaker.DeploymentProcess
ValueTask DeploymentProcess(Job job, IDatabaseContextFactory databaseContextFactory, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Create and a compile job and insert it into the database. Meant to be called by a IJobManager.
diff --git a/_i_engine_installer_8cs_source.html b/_i_engine_installer_8cs_source.html index 66ef72c7ac..42e7a1aff5 100644 --- a/_i_engine_installer_8cs_source.html +++ b/_i_engine_installer_8cs_source.html @@ -89,7 +89,7 @@ $(function() {
13 {
21 IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask);
22
-
30 ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken);
+
30 ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken);
31
40 ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken);
41
@@ -101,12 +101,12 @@ $(function() {
66 }
67}
Tgstation.Server.Api.Models.EngineVersion
Information about an engine installation.
Definition: EngineVersion.cs:14
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Components.Engine.IEngineInstallation
Represents a BYOND installation.
Definition: IEngineInstallation.cs:18
Tgstation.Server.Host.Components.Engine.IEngineInstaller
For downloading and installing game engines for a given system.
Definition: IEngineInstaller.cs:13
Tgstation.Server.Host.Components.Engine.IEngineInstaller.CreateInstallation
IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
Creates an IEngineInstallation for a given version .
+
Tgstation.Server.Host.Components.Engine.IEngineInstaller.DownloadVersion
ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version .
Tgstation.Server.Host.Components.Engine.IEngineInstaller.UpgradeInstallation
ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
Does actions necessary to get upgrade a version installed by a previous version of TGS.
-
Tgstation.Server.Host.Components.Engine.IEngineInstaller.DownloadVersion
ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version .
Tgstation.Server.Host.Components.Engine.IEngineInstaller.Install
ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Does actions necessary to get an extracted installation working.
Tgstation.Server.Host.Components.Engine.IEngineInstaller.TrustDmbPath
ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken)
Add a given fullDmbPath to the trusted DMBs list in BYOND's config.
Tgstation.Server.Host.Components.Engine.IEngineInstaller.CleanCache
Task CleanCache(CancellationToken cancellationToken)
Attempts to cleans the engine's cache folder for the system.
diff --git a/_i_engine_manager_8cs_source.html b/_i_engine_manager_8cs_source.html index d9cbfdedd4..0ac012ed13 100644 --- a/_i_engine_manager_8cs_source.html +++ b/_i_engine_manager_8cs_source.html @@ -94,8 +94,8 @@ $(function() {
22
26 IReadOnlyList<EngineVersion> InstalledVersions { get; }
27
-
37 ValueTask ChangeVersion(
-
38 JobProgressReporter? progressReporter,
+
37 ValueTask ChangeVersion(
+
38 JobProgressReporter progressReporter,
39 EngineVersion version,
40 Stream? customVersionStream,
41 bool allowInstallation,
@@ -112,13 +112,13 @@ $(function() {
IDisposable
Stream
Tgstation.Server.Api.Models.EngineVersion
Information about an engine installation.
Definition: EngineVersion.cs:14
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Components.Engine.IEngineManager
For managing the engine installations.
Definition: IEngineManager.cs:17
Tgstation.Server.Host.Components.Engine.IEngineManager.DeleteVersion
ValueTask DeleteVersion(JobProgressReporter progressReporter, EngineVersion version, CancellationToken cancellationToken)
Deletes a given version from the disk.
Tgstation.Server.Host.Components.Engine.IEngineManager.InstalledVersions
IReadOnlyList< EngineVersion > InstalledVersions
The installed EngineVersions.
Definition: IEngineManager.cs:26
Tgstation.Server.Host.Components.Engine.IEngineManager.ActiveVersion
EngineVersion? ActiveVersion
The currently active EngineVersion.
Definition: IEngineManager.cs:21
+
Tgstation.Server.Host.Components.Engine.IEngineManager.ChangeVersion
ValueTask ChangeVersion(JobProgressReporter progressReporter, EngineVersion version, Stream? customVersionStream, bool allowInstallation, CancellationToken cancellationToken)
Change the active EngineVersion.
Tgstation.Server.Host.Components.Engine.IEngineManager.UseExecutables
ValueTask< IEngineExecutableLock > UseExecutables(EngineVersion? requiredVersion, string? trustDmbFullPath, CancellationToken cancellationToken)
Lock the current installation's location and return a IEngineExecutableLock.
-
Tgstation.Server.Host.Components.Engine.IEngineManager.ChangeVersion
ValueTask ChangeVersion(JobProgressReporter? progressReporter, EngineVersion version, Stream? customVersionStream, bool allowInstallation, CancellationToken cancellationToken)
Change the active EngineVersion.
Tgstation.Server.Host.Components.IComponentService
Represents a component meant to be started and stopped by its parent component.
Definition: IComponentService.cs:9
Tgstation.Server.Api.Models
Definition: ChatChannel.cs:6
Tgstation.Server.Host.Components.Engine
Definition: ByondInstallation.cs:12
diff --git a/_i_process_base_8cs_source.html b/_i_process_base_8cs_source.html index 5f6e7e308b..269c861c3b 100644 --- a/_i_process_base_8cs_source.html +++ b/_i_process_base_8cs_source.html @@ -86,7 +86,7 @@ $(function() {
10 {
14 Task<int?> Lifetime { get; }
15
-
19 long MemoryUsage { get; }
+
19 long? MemoryUsage { get; }
20
25 void AdjustPriority(bool higher);
26
@@ -101,7 +101,7 @@ $(function() {
Tgstation.Server.Host.System.IProcessBase.SuspendProcess
void SuspendProcess()
Suspends the process.
Tgstation.Server.Host.System.IProcessBase.ResumeProcess
void ResumeProcess()
Resumes the process.
Tgstation.Server.Host.System.IProcessBase.AdjustPriority
void AdjustPriority(bool higher)
Set's the owned global::System.Diagnostics.Process.PriorityClass to a non-normal value.
-
Tgstation.Server.Host.System.IProcessBase.MemoryUsage
long MemoryUsage
Gets the process' memory usage in bytes.
Definition: IProcessBase.cs:19
+
Tgstation.Server.Host.System.IProcessBase.MemoryUsage
long? MemoryUsage
Gets the process' memory usage in bytes.
Definition: IProcessBase.cs:19
Tgstation.Server.Host.System.IProcessBase.CreateDump
ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
Create a dump file of the process.
Tgstation.Server.Host.System.IProcessBase.Lifetime
Task< int?> Lifetime
The Task<TResult> resulting in the exit code of the process or null if the process was detached.
Definition: IProcessBase.cs:14
Tgstation.Server.Host.System
Definition: AssemblyInformationProvider.cs:9
diff --git a/_i_repository_8cs_source.html b/_i_repository_8cs_source.html index b878a83733..14a65fbb84 100644 --- a/_i_repository_8cs_source.html +++ b/_i_repository_8cs_source.html @@ -98,13 +98,13 @@ $(function() {
34
41 Task<bool> IsSha(string committish, CancellationToken cancellationToken);
42
-
54 ValueTask CheckoutObject(
+
54 ValueTask CheckoutObject(
55 string committish,
56 string? username,
57 string? password,
58 bool updateSubmodules,
59 bool moveCurrentReference,
-
60 JobProgressReporter? progressReporter,
+
60 JobProgressReporter progressReporter,
61 CancellationToken cancellationToken);
62
75 ValueTask<TestMergeResult> AddTestMerge(
@@ -117,8 +117,8 @@ $(function() {
82 JobProgressReporter progressReporter,
83 CancellationToken cancellationToken);
84
-
94 ValueTask FetchOrigin(
-
95 JobProgressReporter? progressReporter,
+
94 ValueTask FetchOrigin(
+
95 JobProgressReporter progressReporter,
96 string? username,
97 string? password,
98 bool deploymentPipeline,
@@ -162,7 +162,7 @@ $(function() {
198}
IDisposable
Tgstation.Server.Api.Models.TestMergeParameters
Parameters for creating a TestMerge.
Definition: TestMergeParameters.cs:9
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Components.Repository.IGitRemoteAdditionalInformation
Additional information from git remotes.
Definition: IGitRemoteAdditionalInformation.cs:13
Tgstation.Server.Host.Components.Repository.IRepository
Represents an on-disk git repository.
Definition: IRepository.cs:14
Tgstation.Server.Host.Components.Repository.IRepository.TimestampCommit
Task< DateTimeOffset > TimestampCommit(string sha, CancellationToken cancellationToken)
Gets the DateTimeOffset a given sha was created on.
@@ -176,9 +176,9 @@ $(function() {
Tgstation.Server.Host.Components.Repository.IRepository.Head
string Head
The SHA of the IRepository HEAD.
Definition: IRepository.cs:23
Tgstation.Server.Host.Components.Repository.IRepository.ResetToSha
Task ResetToSha(string sha, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Requires the current HEAD to be a reference. Hard resets the reference to the given sha.
Tgstation.Server.Host.Components.Repository.IRepository.CommittishIsParent
Task< bool > CommittishIsParent(string committish, CancellationToken cancellationToken)
Check if a given committish is a parent of the current Head.
-
Tgstation.Server.Host.Components.Repository.IRepository.CheckoutObject
ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
Checks out a given committish .
+
Tgstation.Server.Host.Components.Repository.IRepository.CheckoutObject
ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Checks out a given committish .
Tgstation.Server.Host.Components.Repository.IRepository.IsSha
Task< bool > IsSha(string committish, CancellationToken cancellationToken)
Checks if a given committish is a sha.
-
Tgstation.Server.Host.Components.Repository.IRepository.FetchOrigin
ValueTask FetchOrigin(JobProgressReporter? progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Fetch commits from the origin repository.
+
Tgstation.Server.Host.Components.Repository.IRepository.FetchOrigin
ValueTask FetchOrigin(JobProgressReporter progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Fetch commits from the origin repository.
Tgstation.Server.Host.Components.Repository.IRepository.Origin
Uri Origin
The current origin remote the IRepository is using.
Definition: IRepository.cs:33
Tgstation.Server.Host.Components.Repository.IRepository.AddTestMerge
ValueTask< TestMergeResult > AddTestMerge(TestMergeParameters testMergeParameters, string committerName, string committerEmail, string? username, string? password, bool updateSubmodules, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Attempt to merge the revision specified by a given set of testMergeParameters into HEAD.
Tgstation.Server.Api.Models
Definition: ChatChannel.cs:6
diff --git a/_i_repository_manager_8cs_source.html b/_i_repository_manager_8cs_source.html index 0673ff0e0c..e6ae8d45b8 100644 --- a/_i_repository_manager_8cs_source.html +++ b/_i_repository_manager_8cs_source.html @@ -93,12 +93,12 @@ $(function() {
23
29 ValueTask<IRepository?> LoadRepository(CancellationToken cancellationToken);
30
-
42 ValueTask<IRepository?> CloneRepository(
+
42 ValueTask<IRepository?> CloneRepository(
43 Uri url,
44 string? initialBranch,
45 string? username,
46 string? password,
-
47 JobProgressReporter? progressReporter,
+
47 JobProgressReporter progressReporter,
48 bool recurseSubmodules,
49 CancellationToken cancellationToken);
50
@@ -106,9 +106,9 @@ $(function() {
57 }
58}
IDisposable
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Components.Repository.IRepositoryManager
Factory for creating and loading IRepositorys.
Definition: IRepositoryManager.cs:13
-
Tgstation.Server.Host.Components.Repository.IRepositoryManager.CloneRepository
ValueTask< IRepository?> CloneRepository(Uri url, string? initialBranch, string? username, string? password, JobProgressReporter? progressReporter, bool recurseSubmodules, CancellationToken cancellationToken)
Clone the repository at url .
+
Tgstation.Server.Host.Components.Repository.IRepositoryManager.CloneRepository
ValueTask< IRepository?> CloneRepository(Uri url, string? initialBranch, string? username, string? password, JobProgressReporter progressReporter, bool recurseSubmodules, CancellationToken cancellationToken)
Clone the repository at url .
Tgstation.Server.Host.Components.Repository.IRepositoryManager.CloneInProgress
bool CloneInProgress
If a CloneRepository(Uri, string, string, string, JobProgressReporter, bool, CancellationToken) opera...
Definition: IRepositoryManager.cs:22
Tgstation.Server.Host.Components.Repository.IRepositoryManager.LoadRepository
ValueTask< IRepository?> LoadRepository(CancellationToken cancellationToken)
Attempt to load the IRepository from the default location.
Tgstation.Server.Host.Components.Repository.IRepositoryManager.DeleteRepository
ValueTask DeleteRepository(CancellationToken cancellationToken)
Delete the current repository.
diff --git a/_job_entrypoint_8cs_source.html b/_job_entrypoint_8cs_source.html index 78d73be820..9c90610055 100644 --- a/_job_entrypoint_8cs_source.html +++ b/_job_entrypoint_8cs_source.html @@ -93,7 +93,7 @@ $(function() {
23 JobProgressReporter progressReporter,
24 CancellationToken cancellationToken);
25}
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Models.Job
Definition: Job.cs:16
Tgstation.Server.Host.Components.IInstanceCore
For interacting with the instance services.
Definition: IInstanceCore.cs:16
Tgstation.Server.Host.Database.IDatabaseContextFactory
Factory for scoping usage of IDatabaseContexts. Meant for use by Components.
Definition: IDatabaseContextFactory.cs:10
diff --git a/_job_progress_reporter_8cs_source.html b/_job_progress_reporter_8cs_source.html index a501cf3919..1c25b73303 100644 --- a/_job_progress_reporter_8cs_source.html +++ b/_job_progress_reporter_8cs_source.html @@ -80,121 +80,209 @@ $(function() { Go to the documentation of this file.
1using System;
2
3using Microsoft.Extensions.Logging;
-
4
-
5using Tgstation.Server.Host.Models;
-
6
-
7namespace Tgstation.Server.Host.Jobs
-
8{
-
12 public sealed class JobProgressReporter
-
13 {
-
17 public string? StageName
-
18 {
-
19 get => stageName;
-
20 set
-
21 {
-
22 if (stageName == value)
-
23 return;
-
24
-
25 stageName = value;
-
26 callback(stageName, lastProgress);
-
27 }
-
28 }
-
29
-
33 readonly ILogger<JobProgressReporter> logger;
-
34
-
38 readonly Action<string?, double?> callback;
-
39
-
43 string? stageName;
-
44
-
48 double? lastProgress;
-
49
-
53 double sectionProgression;
-
54
-
61 public JobProgressReporter(ILogger<JobProgressReporter> logger, string? stageName, Action<string?, double?> callback)
-
62 {
-
63 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
-
64 this.callback = callback ?? throw new ArgumentNullException(nameof(callback));
-
65 StageName = stageName;
-
66
-
67 logger.LogDebug("Job progress reporter created. Stage: {stageName}", stageName ?? "(null)");
-
68 }
-
69
-
74 public void ReportProgress(double? progress)
-
75 {
-
76 var clampedProgress = progress;
-
77 if (progress.HasValue)
-
78 if (progress > 1 || progress < 0)
-
79 {
-
80 logger.LogError(
-
81 new ArgumentOutOfRangeException(nameof(progress), progress, "Progress must be a value from 0-1!"),
-
82 "Invalid progress value for stage {stageName}",
-
83 StageName ?? "(null)");
-
84 clampedProgress = null;
-
85 }
-
86 else
-
87 sectionProgression = progress.Value;
+
4using Microsoft.Extensions.Logging.Abstractions;
+
5
+
6using Tgstation.Server.Host.Models;
+
7
+
8namespace Tgstation.Server.Host.Jobs
+
9{
+
13 public sealed class JobProgressReporter : IDisposable
+
14 {
+
18 public string? StageName
+
19 {
+
20 get => stageName;
+
21 set
+
22 {
+
23 if (stageName == value)
+
24 return;
+
25
+
26 stageName = value;
+
27 callback(stageName, lastProgress);
+
28 }
+
29 }
+
30
+
34 readonly ILogger<JobProgressReporter> logger;
+
35
+
39 readonly Action<string?, double?> callback;
+
40
+
44 string? stageName;
+
45
+
49 double? lastProgress;
+
50
+
54 double sectionProgression;
+
55
+
59 double? sectionReservations;
+
60
+
65 public JobProgressReporter()
+
66 : this(
+
67 NullLogger<JobProgressReporter>.Instance,
+
68 null,
+
69 (_, _) => { },
+
70 false)
+
71 {
+
72 }
+
73
+
80 public JobProgressReporter(ILogger<JobProgressReporter> logger, string? stageName, Action<string?, double?> callback)
+
81 : this(
+
82 logger,
+
83 stageName,
+
84 callback,
+
85 true)
+
86 {
+
87 }
88
-
89 callback(StageName, clampedProgress);
-
90 lastProgress = clampedProgress;
-
91 }
-
92
-
100 public JobProgressReporter CreateSection(string? newStageName, double percentage)
-
101 {
-
102 if (percentage > 1 || percentage < 0)
-
103 {
-
104 logger.LogError(
-
105 new ArgumentOutOfRangeException(nameof(percentage), percentage, "Percentage must be a value from 0-1!"),
-
106 "Invalid percentage value for stage {newStageName}! Clamping...",
-
107 newStageName ?? "(null)");
+
96 private JobProgressReporter(ILogger<JobProgressReporter> logger, string? stageName, Action<string?, double?> callback, bool setStageName)
+
97 {
+
98 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+
99 this.callback = callback ?? throw new ArgumentNullException(nameof(callback));
+
100 if (setStageName)
+
101 {
+
102 StageName = stageName;
+
103 }
+
104 else
+
105 {
+
106 this.stageName = stageName;
+
107 }
108
-
109 percentage = Math.Min(Math.Max(percentage, 0.0), 1.0);
-
110 }
+
109 logger.LogDebug("Job progress reporter created. Stage: {stageName}", stageName ?? "(null)");
+
110 }
111
-
112 var childBaseProgress = sectionProgression;
-
113 if (percentage + childBaseProgress > 1.0)
-
114 {
-
115 var remainingPercentage = 1.0 - childBaseProgress;
-
116 logger.LogError(
-
117 "Stage {newStageName} is overbudgeted ({budget}/{remainingPercentage})! Clamping...",
-
118 newStageName,
-
119 percentage,
-
120 remainingPercentage);
-
121 percentage = remainingPercentage;
-
122 }
-
123
-
124 var newReporter = new JobProgressReporter(
-
125 logger,
-
126 newStageName,
-
127 (currentStage, progress) =>
-
128 {
-
129 currentStage ??= StageName;
-
130 if (!progress.HasValue)
-
131 {
-
132 callback(currentStage, null);
-
133 return;
-
134 }
-
135
-
136 var childLocalProgress = progress.Value * percentage;
-
137
-
138 sectionProgression = childLocalProgress + childBaseProgress;
-
139 callback(currentStage, sectionProgression);
-
140 });
-
141
-
142 newReporter.ReportProgress(0);
-
143 return newReporter;
-
144 }
-
145 }
-
146}
-
Progress reporter for a Job.
-
double? lastProgress
The last progress value pushed into the callback.
-
double sectionProgression
The total progress reported so far in this section.
-
string? StageName
The name of the current stage.
-
readonly Action< string?, double?> callback
Progress reporter callback taking a description of what the job is currently doing and the (optional)...
-
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
-
JobProgressReporter(ILogger< JobProgressReporter > logger, string? stageName, Action< string?, double?> callback)
Initializes a new instance of the JobProgressReporter class.
-
readonly ILogger< JobProgressReporter > logger
The ILogger<TCategoryName> for the JobProgressReporter.
-
void ReportProgress(double? progress)
Report progress.
-
string? stageName
Backing field for StageName.
+
113 public void Dispose()
+
114 {
+
115 if (sectionReservations.HasValue)
+
116 if (sectionReservations.Value != 1.0)
+
117 {
+
118 // not an error, processes can throw
+
119 sectionReservations = null;
+
120 }
+
121 else if (sectionProgression < 1.0)
+
122 {
+
123 logger.LogError(
+
124 new InvalidOperationException($"Parent progress reporter has child sections that didn't complete! Current: {sectionProgression}"),
+
125 "TGS BUG: Progress reporter children didn't complete!");
+
126 sectionReservations = null;
+
127 }
+
128
+
129 if (!sectionReservations.HasValue)
+
130 ReportProgress(1);
+
131 }
+
132
+
137 public void ReportProgress(double? progress)
+
138 {
+
139 if (sectionReservations.HasValue)
+
140 if (progress == 0)
+
141 {
+
142 // might be a stage reset
+
143 sectionReservations = null;
+
144 }
+
145 else
+
146 {
+
147 logger.LogError(
+
148 new InvalidOperationException("Progress reporter is reporting progress with existing nested sections!"),
+
149 "TGS BUG: A progress reporter is using mixed local and nested progress, this is not supported");
+
150 }
+
151
+
152 var clampedProgress = progress;
+
153 if (progress.HasValue)
+
154 if (progress > 1 || progress < 0)
+
155 {
+
156 logger.LogError(
+
157 new ArgumentOutOfRangeException(nameof(progress), progress, "Progress must be a value from 0-1!"),
+
158 "TGS BUG: Invalid progress value for stage {stageName}",
+
159 StageName ?? "(null)");
+
160 clampedProgress = null;
+
161 }
+
162 else
+
163 sectionProgression = progress.Value;
+
164
+
165 callback(StageName, clampedProgress);
+
166 lastProgress = clampedProgress;
+
167 }
+
168
+
176 public JobProgressReporter CreateSection(string? newStageName, double percentage)
+
177 {
+
178 if (percentage > 1 || percentage < 0)
+
179 {
+
180 logger.LogError(
+
181 new ArgumentOutOfRangeException(nameof(percentage), percentage, "Percentage must be a value from 0-1!"),
+
182 "TGS BUG: Invalid percentage value for stage {newStageName}! Clamping...",
+
183 newStageName ?? "(null)");
+
184
+
185 percentage = Math.Min(Math.Max(percentage, 0.0), 1.0);
+
186 }
+
187
+
188 if (!sectionReservations.HasValue)
+
189 {
+
190 if (sectionProgression != 0)
+
191 {
+
192 logger.LogError(
+
193 new InvalidOperationException("Progress reporter is creating a section with local progress!"),
+
194 "TGS BUG: A progress reporter is using mixed local and nested progress, this is not supported");
+
195 }
+
196
+
197 sectionReservations = 0;
+
198 }
+
199
+
200 // floating point >.<
+
201 if (percentage + sectionReservations.Value > 1.0001)
+
202 {
+
203 var remainingPercentage = 1.0 - sectionReservations.Value;
+
204 logger.LogError(
+
205 "Stage {newStageName} is overbudgeted ({budget}/{remainingPercentage})! Clamping...",
+
206 newStageName,
+
207 percentage,
+
208 remainingPercentage);
+
209 percentage = remainingPercentage;
+
210 }
+
211
+
212 Math.Min(sectionReservations.Value + percentage, 1);
+
213
+
214 var childLocalProgress = 0.0;
+
215 var newReporter = new JobProgressReporter(
+
216 logger,
+
217 newStageName,
+
218 (currentStage, progress) =>
+
219 {
+
220 currentStage ??= StageName;
+
221 if (!progress.HasValue)
+
222 {
+
223 callback(currentStage, null);
+
224 return;
+
225 }
+
226
+
227 var progressWithoutChild = sectionProgression - childLocalProgress;
+
228 childLocalProgress = progress.Value * percentage;
+
229
+
230 // floating point >.<
+
231 sectionProgression = Math.Min(progressWithoutChild + childLocalProgress, 1);
+
232 if (sectionProgression > 9.9999)
+
233 sectionProgression = 1;
+
234
+
235 callback(currentStage, sectionProgression);
+
236 },
+
237 false);
+
238
+
239 newReporter.ReportProgress(0);
+
240 return newReporter;
+
241 }
+
242 }
+
243}
+
+
Progress reporter for a Job.
+
double? lastProgress
The last progress value pushed into the callback.
+
double sectionProgression
The total progress reported so far in this section.
+
string? StageName
The name of the current stage.
+
readonly Action< string?, double?> callback
Progress reporter callback taking a description of what the job is currently doing and the (optional)...
+
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
+
JobProgressReporter(ILogger< JobProgressReporter > logger, string? stageName, Action< string?, double?> callback)
Initializes a new instance of the JobProgressReporter class.
+
readonly ILogger< JobProgressReporter > logger
The ILogger<TCategoryName> for the JobProgressReporter.
+
void Dispose()
+
JobProgressReporter(ILogger< JobProgressReporter > logger, string? stageName, Action< string?, double?> callback, bool setStageName)
Initializes a new instance of the JobProgressReporter class.
+
JobProgressReporter()
Initializes a new instance of the JobProgressReporter class.
+
double? sectionReservations
The total progress reserved for use in this section.
+
void ReportProgress(double? progress)
Report progress.
+
string? stageName
Backing field for StageName.
+
Represents an Api.Models.Instance in the database.
Definition: Instance.cs:11
Definition: IJobManager.cs:8
Definition: ChatBot.cs:9
diff --git a/_job_service_8cs_source.html b/_job_service_8cs_source.html index 6100983377..7de5bbc3bb 100644 --- a/_job_service_8cs_source.html +++ b/_job_service_8cs_source.html @@ -482,101 +482,103 @@ $(function() {
460 QueueHubUpdate(job.ToApi(), false);
461
462 logger.LogTrace("Starting job...");
-
463 await operation(
-
464 instanceCoreProvider.GetInstance(job.Instance!),
-
465 databaseContextFactory,
-
466 job,
-
467 new JobProgressReporter(
-
468 loggerFactory.CreateLogger<JobProgressReporter>(),
-
469 null,
-
470 UpdateProgress),
-
471 cancellationToken);
-
472
-
473 logger.LogDebug("Job {jobId} completed!", job.Id);
-
474 result = true;
-
475 }
-
476 catch (OperationCanceledException ex)
-
477 {
-
478 logger.LogDebug(ex, "Job {jobId} cancelled!", job.Id);
-
479 job.Cancelled = true;
-
480 }
-
481 catch (JobException e)
-
482 {
-
483 job.ErrorCode = e.ErrorCode;
-
484 job.ExceptionDetails = String.IsNullOrWhiteSpace(e.Message) ? e.InnerException?.Message : e.Message + $" (Inner exception: {e.InnerException?.Message})";
-
485 LogException(e);
-
486 }
-
487 catch (Exception e)
-
488 {
-
489 job.ExceptionDetails = e.ToString();
-
490 LogException(e);
-
491 }
-
492
-
493 try
-
494 {
-
495 await databaseContextFactory.UseContext(async databaseContext =>
-
496 {
-
497 var attachedJob = new Job(jid);
-
498
-
499 databaseContext.Jobs.Attach(attachedJob);
-
500 attachedJob.StoppedAt = DateTimeOffset.UtcNow;
-
501 attachedJob.ExceptionDetails = job.ExceptionDetails;
-
502 attachedJob.ErrorCode = job.ErrorCode;
-
503 attachedJob.Cancelled = job.Cancelled;
-
504
-
505 // DCT: Cancellation token is for job, operation should always run
-
506 await databaseContext.Save(CancellationToken.None);
-
507 });
-
508
-
509 // Resetting the context here because I CBA to worry if the cache is being used
-
510 await databaseContextFactory.UseContext(async databaseContext =>
-
511 {
-
512 // Cancellation might be set in another async context
-
513 // Also, startedby could have been renamed
-
514 // forced to reload here for the final hub update
-
515 // DCT: Cancellation token is for job, operation should always run
-
516 var finalJob = await databaseContext
-
517 .Jobs
-
518 .AsQueryable()
-
519 .Include(x => x.Instance)
-
520 .Include(x => x.StartedBy)
-
521 .Include(x => x.CancelledBy)
-
522 .Where(dbJob => dbJob.Id == jid)
-
523 .FirstAsync(CancellationToken.None);
-
524 QueueHubUpdate(finalJob.ToApi(), true);
-
525 });
-
526 }
-
527 catch
-
528 {
-
529 lock (hubUpdateActions)
-
530 hubUpdateActions.Remove(jid);
-
531
-
532 throw;
-
533 }
-
534
-
535 try
-
536 {
-
537 await hubUpdatesTask;
-
538 }
-
539 catch (Exception ex)
-
540 {
-
541 logger.LogError(ex, "Error in hub updates chain task!");
-
542 }
-
543
-
544 return result;
-
545 }
-
546 finally
-
547 {
-
548 lock (synchronizationLock)
-
549 {
-
550 var handler = jobs[jid];
-
551 jobs.Remove(jid);
-
552 handler.Dispose();
-
553 }
-
554 }
-
555 }
-
556 }
-
557}
+
463 using var progressReporter = new JobProgressReporter(
+
464 loggerFactory.CreateLogger<JobProgressReporter>(),
+
465 null,
+
466 UpdateProgress);
+
467 using var innerReporter = progressReporter.CreateSection(null, 1.0);
+
468 await operation(
+
469 instanceCoreProvider.GetInstance(job.Instance!),
+
470 databaseContextFactory,
+
471 job,
+
472 innerReporter,
+
473 cancellationToken);
+
474
+
475 logger.LogDebug("Job {jobId} completed!", job.Id);
+
476 result = true;
+
477 }
+
478 catch (OperationCanceledException ex)
+
479 {
+
480 logger.LogDebug(ex, "Job {jobId} cancelled!", job.Id);
+
481 job.Cancelled = true;
+
482 }
+
483 catch (JobException e)
+
484 {
+
485 job.ErrorCode = e.ErrorCode;
+
486 job.ExceptionDetails = String.IsNullOrWhiteSpace(e.Message) ? e.InnerException?.Message : e.Message + $" (Inner exception: {e.InnerException?.Message})";
+
487 LogException(e);
+
488 }
+
489 catch (Exception e)
+
490 {
+
491 job.ExceptionDetails = e.ToString();
+
492 LogException(e);
+
493 }
+
494
+
495 try
+
496 {
+
497 await databaseContextFactory.UseContext(async databaseContext =>
+
498 {
+
499 var attachedJob = new Job(jid);
+
500
+
501 databaseContext.Jobs.Attach(attachedJob);
+
502 attachedJob.StoppedAt = DateTimeOffset.UtcNow;
+
503 attachedJob.ExceptionDetails = job.ExceptionDetails;
+
504 attachedJob.ErrorCode = job.ErrorCode;
+
505 attachedJob.Cancelled = job.Cancelled;
+
506
+
507 // DCT: Cancellation token is for job, operation should always run
+
508 await databaseContext.Save(CancellationToken.None);
+
509 });
+
510
+
511 // Resetting the context here because I CBA to worry if the cache is being used
+
512 await databaseContextFactory.UseContext(async databaseContext =>
+
513 {
+
514 // Cancellation might be set in another async context
+
515 // Also, startedby could have been renamed
+
516 // forced to reload here for the final hub update
+
517 // DCT: Cancellation token is for job, operation should always run
+
518 var finalJob = await databaseContext
+
519 .Jobs
+
520 .AsQueryable()
+
521 .Include(x => x.Instance)
+
522 .Include(x => x.StartedBy)
+
523 .Include(x => x.CancelledBy)
+
524 .Where(dbJob => dbJob.Id == jid)
+
525 .FirstAsync(CancellationToken.None);
+
526 QueueHubUpdate(finalJob.ToApi(), true);
+
527 });
+
528 }
+
529 catch
+
530 {
+
531 lock (hubUpdateActions)
+
532 hubUpdateActions.Remove(jid);
+
533
+
534 throw;
+
535 }
+
536
+
537 try
+
538 {
+
539 await hubUpdatesTask;
+
540 }
+
541 catch (Exception ex)
+
542 {
+
543 logger.LogError(ex, "Error in hub updates chain task!");
+
544 }
+
545
+
546 return result;
+
547 }
+
548 finally
+
549 {
+
550 lock (synchronizationLock)
+
551 {
+
552 var handler = jobs[jid];
+
553 jobs.Remove(jid);
+
554 handler.Dispose();
+
555 }
+
556 }
+
557 }
+
558 }
+
559}
Exception
IDisposable
Tgstation.Server.Api.Models.EntityId.Id
virtual ? long Id
The ID of the entity.
Definition: EntityId.cs:13
@@ -594,7 +596,7 @@ $(function() {
Tgstation.Server.Host.Jobs.JobHandler.Cancel
void Cancel()
Cancels task.
Tgstation.Server.Host.Jobs.JobHandler.Wait
Task< bool > Wait(CancellationToken cancellationToken)
Wait for task to complete.
Definition: JobHandler.cs:60
Tgstation.Server.Host.Jobs.JobHandler.Started
bool Started
If the job has started.
Definition: JobHandler.cs:15
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
Tgstation.Server.Host.Jobs.JobService
Definition: JobService.cs:29
Tgstation.Server.Host.Jobs.JobService.hub
readonly IConnectionMappedHubContext< JobsHub, IJobsHub > hub
The IHubContext for the JobsHub.
Definition: JobService.cs:38
Tgstation.Server.Host.Jobs.JobService.RunJob
async Task< bool > RunJob(Job job, JobEntrypoint operation, CancellationToken cancellationToken)
Runner for JobHandlers.
Definition: JobService.cs:361
diff --git a/_open_dream_installer_8cs_source.html b/_open_dream_installer_8cs_source.html index 6cd8869e50..e2153674b5 100644 --- a/_open_dream_installer_8cs_source.html +++ b/_open_dream_installer_8cs_source.html @@ -160,230 +160,247 @@ $(function() {
132 version);
133 }
134
-
136 public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
+
136 public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
137 {
138 CheckVersionValidity(version);
-
139
-
140 // get a lock on a system wide OD repo
-
141 Logger.LogTrace("Cloning OD repo...");
-
142
-
143 var progressSection1 = jobProgressReporter?.CreateSection("Updating OpenDream git repository", 0.5f);
-
144
-
145 var repo = await repositoryManager.CloneRepository(
-
146 GeneralConfiguration.OpenDreamGitUrl,
-
147 null,
-
148 null,
-
149 null,
-
150 progressSection1,
-
151 true,
-
152 cancellationToken);
-
153
-
154 try
-
155 {
-
156 if (repo == null)
-
157 {
-
158 Logger.LogTrace("OD repo seems to already exist, attempting load and fetch...");
-
159 repo = await repositoryManager.LoadRepository(cancellationToken);
-
160 if (repo == null)
-
161 throw new JobException("Can't load OpenDream repository! Please delete cache from disk!");
+
139 ArgumentNullException.ThrowIfNull(jobProgressReporter);
+
140
+
141 // get a lock on a system wide OD repo
+
142 Logger.LogTrace("Cloning OD repo...");
+
143
+
144 var progressSection1 = jobProgressReporter.CreateSection("Updating OpenDream git repository", 0.5f);
+
145 IRepository? repo;
+
146 try
+
147 {
+
148 repo = await repositoryManager.CloneRepository(
+
149 GeneralConfiguration.OpenDreamGitUrl,
+
150 null,
+
151 null,
+
152 null,
+
153 progressSection1,
+
154 true,
+
155 cancellationToken);
+
156 }
+
157 catch
+
158 {
+
159 progressSection1.Dispose();
+
160 throw;
+
161 }
162
-
163 await repo!.FetchOrigin(
-
164 progressSection1,
-
165 null,
-
166 null,
-
167 false,
-
168 cancellationToken);
-
169 }
-
170
-
171 var progressSection2 = jobProgressReporter?.CreateSection("Checking out OpenDream version", 0.5f);
-
172
-
173 var committish = version.SourceSHA
-
174 ?? $"{GeneralConfiguration.OpenDreamGitTagPrefix}{version.Version!.Semver()}";
-
175
-
176 await repo.CheckoutObject(
-
177 committish,
-
178 null,
-
179 null,
-
180 true,
-
181 false,
-
182 progressSection2,
-
183 cancellationToken);
-
184
-
185 if (!await repo.CommittishIsParent("tgs-min-compat", cancellationToken))
-
186 throw new JobException(ErrorCode.OpenDreamTooOld);
+
163 try
+
164 {
+
165 if (repo == null)
+
166 {
+
167 Logger.LogTrace("OD repo seems to already exist, attempting load and fetch...");
+
168 repo = await repositoryManager.LoadRepository(cancellationToken);
+
169 if (repo == null)
+
170 throw new JobException("Can't load OpenDream repository! Please delete cache from disk!");
+
171
+
172 await repo!.FetchOrigin(
+
173 progressSection1,
+
174 null,
+
175 null,
+
176 false,
+
177 cancellationToken);
+
178 }
+
179
+
180 progressSection1.Dispose();
+
181 progressSection1 = null;
+
182
+
183 using (var progressSection2 = jobProgressReporter.CreateSection("Checking out OpenDream version", 0.5f))
+
184 {
+
185 var committish = version.SourceSHA
+
186 ?? $"{GeneralConfiguration.OpenDreamGitTagPrefix}{version.Version!.Semver()}";
187
-
188 return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory);
-
189 }
-
190 catch
-
191 {
-
192 repo?.Dispose();
-
193 throw;
-
194 }
-
195 }
-
196
-
198 public override async ValueTask Install(EngineVersion version, string installPath, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
-
199 {
-
200 CheckVersionValidity(version);
-
201 ArgumentNullException.ThrowIfNull(installPath);
-
202 var sourcePath = IOManager.ConcatPath(installPath, InstallationSourceSubDirectory);
-
203
-
204 if (!await IOManager.DirectoryExists(sourcePath, cancellationToken))
-
205 {
-
206 // a zip install that didn't come from us?
-
207 // we want to use the bin dir, so put everything where we expect
-
208 Logger.LogDebug("Correcting extraction location...");
-
209 var dirsTask = IOManager.GetDirectories(installPath, cancellationToken);
-
210 var filesTask = IOManager.GetFiles(installPath, cancellationToken);
-
211 var dirCreateTask = IOManager.CreateDirectory(sourcePath, cancellationToken);
-
212
-
213 await Task.WhenAll(dirsTask, filesTask, dirCreateTask);
-
214
-
215 var dirsMoveTasks = dirsTask
-
216 .Result
-
217 .Select(
-
218 dirPath => IOManager.MoveDirectory(
-
219 dirPath,
-
220 IOManager.ConcatPath(
-
221 sourcePath,
-
222 IOManager.GetFileName(dirPath)),
-
223 cancellationToken));
-
224 var filesMoveTask = filesTask
-
225 .Result
-
226 .Select(
-
227 filePath => IOManager.MoveFile(
-
228 filePath,
-
229 IOManager.ConcatPath(
-
230 sourcePath,
-
231 IOManager.GetFileName(filePath)),
-
232 cancellationToken));
-
233
-
234 await Task.WhenAll(dirsMoveTasks.Concat(filesMoveTask));
-
235 }
-
236
-
237 var dotnetPath = await DotnetHelper.GetDotnetPath(platformIdentifier, IOManager, cancellationToken);
-
238 if (dotnetPath == null)
-
239 throw new JobException(ErrorCode.OpenDreamCantFindDotnet);
-
240
-
241 const string DeployDir = "tgs_deploy";
-
242 int? buildExitCode = null;
-
243 await HandleExtremelyLongPathOperation(
-
244 async shortenedPath =>
-
245 {
-
246 var shortenedDeployPath = IOManager.ConcatPath(shortenedPath, DeployDir);
-
247 await using var buildProcess = await ProcessExecutor.LaunchProcess(
-
248 dotnetPath,
-
249 shortenedPath,
-
250 $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}",
-
251 cancellationToken,
-
252 null,
-
253 null,
-
254 !GeneralConfiguration.OpenDreamSuppressInstallOutput,
-
255 !GeneralConfiguration.OpenDreamSuppressInstallOutput);
-
256
-
257 if (deploymentPipelineProcesses && SessionConfiguration.LowPriorityDeploymentProcesses)
-
258 buildProcess.AdjustPriority(false);
-
259
-
260 using (cancellationToken.Register(() => buildProcess.Terminate()))
-
261 buildExitCode = await buildProcess.Lifetime;
-
262
-
263 string? output;
-
264 if (!GeneralConfiguration.OpenDreamSuppressInstallOutput)
-
265 {
-
266 var buildOutputTask = buildProcess.GetCombinedOutput(cancellationToken);
-
267 if (!buildOutputTask.IsCompleted)
-
268 Logger.LogTrace("OD build complete, waiting for output...");
-
269 output = await buildOutputTask;
-
270 }
-
271 else
-
272 output = "<Build output suppressed by configuration due to not being immediately available>";
+
188 await repo.CheckoutObject(
+
189 committish,
+
190 null,
+
191 null,
+
192 true,
+
193 false,
+
194 progressSection2,
+
195 cancellationToken);
+
196 }
+
197
+
198 if (!await repo.CommittishIsParent("tgs-min-compat", cancellationToken))
+
199 throw new JobException(ErrorCode.OpenDreamTooOld);
+
200
+
201 return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory);
+
202 }
+
203 catch
+
204 {
+
205 repo?.Dispose();
+
206 throw;
+
207 }
+
208 finally
+
209 {
+
210 progressSection1?.Dispose();
+
211 }
+
212 }
+
213
+
215 public override async ValueTask Install(EngineVersion version, string installPath, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
+
216 {
+
217 CheckVersionValidity(version);
+
218 ArgumentNullException.ThrowIfNull(installPath);
+
219 var sourcePath = IOManager.ConcatPath(installPath, InstallationSourceSubDirectory);
+
220
+
221 if (!await IOManager.DirectoryExists(sourcePath, cancellationToken))
+
222 {
+
223 // a zip install that didn't come from us?
+
224 // we want to use the bin dir, so put everything where we expect
+
225 Logger.LogDebug("Correcting extraction location...");
+
226 var dirsTask = IOManager.GetDirectories(installPath, cancellationToken);
+
227 var filesTask = IOManager.GetFiles(installPath, cancellationToken);
+
228 var dirCreateTask = IOManager.CreateDirectory(sourcePath, cancellationToken);
+
229
+
230 await Task.WhenAll(dirsTask, filesTask, dirCreateTask);
+
231
+
232 var dirsMoveTasks = dirsTask
+
233 .Result
+
234 .Select(
+
235 dirPath => IOManager.MoveDirectory(
+
236 dirPath,
+
237 IOManager.ConcatPath(
+
238 sourcePath,
+
239 IOManager.GetFileName(dirPath)),
+
240 cancellationToken));
+
241 var filesMoveTask = filesTask
+
242 .Result
+
243 .Select(
+
244 filePath => IOManager.MoveFile(
+
245 filePath,
+
246 IOManager.ConcatPath(
+
247 sourcePath,
+
248 IOManager.GetFileName(filePath)),
+
249 cancellationToken));
+
250
+
251 await Task.WhenAll(dirsMoveTasks.Concat(filesMoveTask));
+
252 }
+
253
+
254 var dotnetPath = await DotnetHelper.GetDotnetPath(platformIdentifier, IOManager, cancellationToken);
+
255 if (dotnetPath == null)
+
256 throw new JobException(ErrorCode.OpenDreamCantFindDotnet);
+
257
+
258 const string DeployDir = "tgs_deploy";
+
259 int? buildExitCode = null;
+
260 await HandleExtremelyLongPathOperation(
+
261 async shortenedPath =>
+
262 {
+
263 var shortenedDeployPath = IOManager.ConcatPath(shortenedPath, DeployDir);
+
264 await using var buildProcess = await ProcessExecutor.LaunchProcess(
+
265 dotnetPath,
+
266 shortenedPath,
+
267 $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}",
+
268 cancellationToken,
+
269 null,
+
270 null,
+
271 !GeneralConfiguration.OpenDreamSuppressInstallOutput,
+
272 !GeneralConfiguration.OpenDreamSuppressInstallOutput);
273
-
274 Logger.LogDebug(
-
275 "OpenDream build exited with code {exitCode}:{newLine}{output}",
-
276 buildExitCode,
-
277 Environment.NewLine,
-
278 output);
-
279 },
-
280 sourcePath,
-
281 cancellationToken);
-
282
-
283 if (buildExitCode != 0)
-
284 throw new JobException("OpenDream build failed!");
-
285
-
286 var deployPath = IOManager.ConcatPath(sourcePath, DeployDir);
-
287 async ValueTask MoveDirs()
-
288 {
-
289 var dirs = await IOManager.GetDirectories(deployPath, cancellationToken);
-
290 await Task.WhenAll(
-
291 dirs.Select(
-
292 dir => IOManager.MoveDirectory(
-
293 dir,
-
294 IOManager.ConcatPath(
-
295 installPath,
-
296 IOManager.GetFileName(dir)),
-
297 cancellationToken)));
-
298 }
+
274 if (deploymentPipelineProcesses && SessionConfiguration.LowPriorityDeploymentProcesses)
+
275 buildProcess.AdjustPriority(false);
+
276
+
277 using (cancellationToken.Register(() => buildProcess.Terminate()))
+
278 buildExitCode = await buildProcess.Lifetime;
+
279
+
280 string? output;
+
281 if (!GeneralConfiguration.OpenDreamSuppressInstallOutput)
+
282 {
+
283 var buildOutputTask = buildProcess.GetCombinedOutput(cancellationToken);
+
284 if (!buildOutputTask.IsCompleted)
+
285 Logger.LogTrace("OD build complete, waiting for output...");
+
286 output = await buildOutputTask;
+
287 }
+
288 else
+
289 output = "<Build output suppressed by configuration due to not being immediately available>";
+
290
+
291 Logger.LogDebug(
+
292 "OpenDream build exited with code {exitCode}:{newLine}{output}",
+
293 buildExitCode,
+
294 Environment.NewLine,
+
295 output);
+
296 },
+
297 sourcePath,
+
298 cancellationToken);
299
-
300 async ValueTask MoveFiles()
-
301 {
-
302 var files = await IOManager.GetFiles(deployPath, cancellationToken);
-
303 await Task.WhenAll(
-
304 files.Select(
-
305 file => IOManager.MoveFile(
-
306 file,
-
307 IOManager.ConcatPath(
-
308 installPath,
-
309 IOManager.GetFileName(file)),
-
310 cancellationToken)));
-
311 }
-
312
-
313 var dirsMoveTask = MoveDirs();
-
314 var outputFilesMoveTask = MoveFiles();
-
315 await ValueTaskExtensions.WhenAll(dirsMoveTask, outputFilesMoveTask);
-
316 await IOManager.DeleteDirectory(sourcePath, cancellationToken);
-
317 }
-
318
-
320 public override ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
-
321 {
-
322 CheckVersionValidity(version);
-
323 ArgumentNullException.ThrowIfNull(path);
-
324 return ValueTask.CompletedTask;
-
325 }
-
326
-
328 public override ValueTask TrustDmbPath(EngineVersion engineVersion, string fullDmbPath, CancellationToken cancellationToken)
-
329 {
-
330 ArgumentNullException.ThrowIfNull(engineVersion);
-
331 ArgumentNullException.ThrowIfNull(fullDmbPath);
-
332
-
333 Logger.LogTrace("TrustDmbPath is a no-op: {path}", fullDmbPath);
-
334 return ValueTask.CompletedTask;
-
335 }
-
336
-
344 protected virtual ValueTask HandleExtremelyLongPathOperation(
-
345 Func<string, ValueTask> shortenedPathOperation,
-
346 string originalPath,
-
347 CancellationToken cancellationToken)
-
348 => shortenedPathOperation(originalPath); // based god linux has no such weakness
+
300 if (buildExitCode != 0)
+
301 throw new JobException("OpenDream build failed!");
+
302
+
303 var deployPath = IOManager.ConcatPath(sourcePath, DeployDir);
+
304 async ValueTask MoveDirs()
+
305 {
+
306 var dirs = await IOManager.GetDirectories(deployPath, cancellationToken);
+
307 await Task.WhenAll(
+
308 dirs.Select(
+
309 dir => IOManager.MoveDirectory(
+
310 dir,
+
311 IOManager.ConcatPath(
+
312 installPath,
+
313 IOManager.GetFileName(dir)),
+
314 cancellationToken)));
+
315 }
+
316
+
317 async ValueTask MoveFiles()
+
318 {
+
319 var files = await IOManager.GetFiles(deployPath, cancellationToken);
+
320 await Task.WhenAll(
+
321 files.Select(
+
322 file => IOManager.MoveFile(
+
323 file,
+
324 IOManager.ConcatPath(
+
325 installPath,
+
326 IOManager.GetFileName(file)),
+
327 cancellationToken)));
+
328 }
+
329
+
330 var dirsMoveTask = MoveDirs();
+
331 var outputFilesMoveTask = MoveFiles();
+
332 await ValueTaskExtensions.WhenAll(dirsMoveTask, outputFilesMoveTask);
+
333 await IOManager.DeleteDirectory(sourcePath, cancellationToken);
+
334 }
+
335
+
337 public override ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
+
338 {
+
339 CheckVersionValidity(version);
+
340 ArgumentNullException.ThrowIfNull(path);
+
341 return ValueTask.CompletedTask;
+
342 }
+
343
+
345 public override ValueTask TrustDmbPath(EngineVersion engineVersion, string fullDmbPath, CancellationToken cancellationToken)
+
346 {
+
347 ArgumentNullException.ThrowIfNull(engineVersion);
+
348 ArgumentNullException.ThrowIfNull(fullDmbPath);
349
-
356 protected void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath)
-
357 {
-
358 var exeExtension = platformIdentifier.IsWindows
-
359 ? ".exe"
-
360 : String.Empty;
-
361
-
362 serverExePath = IOManager.ConcatPath(
-
363 installationPath,
-
364 BinDir,
-
365 ServerDir,
-
366 $"Robust.Server{exeExtension}");
-
367
-
368 compilerExePath = IOManager.ConcatPath(
-
369 installationPath,
-
370 BinDir,
-
371 InstallationCompilerDirectory,
-
372 $"DMCompiler{exeExtension}");
-
373 }
-
374 }
-
375}
+
350 Logger.LogTrace("TrustDmbPath is a no-op: {path}", fullDmbPath);
+
351 return ValueTask.CompletedTask;
+
352 }
+
353
+
361 protected virtual ValueTask HandleExtremelyLongPathOperation(
+
362 Func<string, ValueTask> shortenedPathOperation,
+
363 string originalPath,
+
364 CancellationToken cancellationToken)
+
365 => shortenedPathOperation(originalPath); // based god linux has no such weakness
+
366
+
373 protected void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath)
+
374 {
+
375 var exeExtension = platformIdentifier.IsWindows
+
376 ? ".exe"
+
377 : String.Empty;
+
378
+
379 serverExePath = IOManager.ConcatPath(
+
380 installationPath,
+
381 BinDir,
+
382 ServerDir,
+
383 $"Robust.Server{exeExtension}");
+
384
+
385 compilerExePath = IOManager.ConcatPath(
+
386 installationPath,
+
387 BinDir,
+
388 InstallationCompilerDirectory,
+
389 $"DMCompiler{exeExtension}");
+
390 }
+
391 }
+
392}
Tgstation.Server.Api.Models.EngineVersion
Information about an engine installation.
Definition: EngineVersion.cs:14
Tgstation.Server.Common.Extensions.ValueTaskExtensions
Extension methods for the ValueTask and ValueTask<TResult> classes.
Definition: ValueTaskExtensions.cs:12
Tgstation.Server.Common.Extensions.ValueTaskExtensions.WhenAll
static async ValueTask WhenAll(IEnumerable< ValueTask > tasks)
Fully await a given list of tasks .
Definition: ValueTaskExtensions.cs:99
@@ -393,21 +410,21 @@ $(function() {
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.Logger
ILogger< EngineInstallerBase > Logger
Gets the ILogger for the EngineInstallerBase.
Definition: EngineInstallerBase.cs:29
Tgstation.Server.Host.Components.Engine.OpenDreamInstallation
Implementation of IEngineInstallation for EngineType.OpenDream.
Definition: OpenDreamInstallation.cs:28
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller
Implementation of IEngineInstaller for EngineType.OpenDream.
Definition: OpenDreamInstaller.cs:25
-
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.GetExecutablePaths
void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath)
Gets the paths to the server and client executables.
Definition: OpenDreamInstaller.cs:356
+
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.GetExecutablePaths
void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath)
Gets the paths to the server and client executables.
Definition: OpenDreamInstaller.cs:373
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.httpClientFactory
readonly IAbstractHttpClientFactory httpClientFactory
The IAbstractHttpClientFactory for the OpenDreamInstaller.
Definition: OpenDreamInstaller.cs:82
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.TargetEngineType
override EngineType TargetEngineType
Definition: OpenDreamInstaller.cs:47
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.platformIdentifier
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the OpenDreamInstaller.
Definition: OpenDreamInstaller.cs:67
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.repositoryManager
readonly IRepositoryManager repositoryManager
The IRepositoryManager for the OpenDream repository.
Definition: OpenDreamInstaller.cs:72
-
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.Install
override async ValueTask Install(EngineVersion version, string installPath, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Does actions necessary to get an extracted installation working. A ValueTask representing the running...
Definition: OpenDreamInstaller.cs:198
-
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.DownloadVersion
override async ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Definition: OpenDreamInstaller.cs:136
-
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.TrustDmbPath
override ValueTask TrustDmbPath(EngineVersion engineVersion, string fullDmbPath, CancellationToken cancellationToken)
Add a given fullDmbPath to the trusted DMBs list in BYOND's config. A ValueTask representing the run...
Definition: OpenDreamInstaller.cs:328
+
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.Install
override async ValueTask Install(EngineVersion version, string installPath, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
Does actions necessary to get an extracted installation working. A ValueTask representing the running...
Definition: OpenDreamInstaller.cs:215
+
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.TrustDmbPath
override ValueTask TrustDmbPath(EngineVersion engineVersion, string fullDmbPath, CancellationToken cancellationToken)
Add a given fullDmbPath to the trusted DMBs list in BYOND's config. A ValueTask representing the run...
Definition: OpenDreamInstaller.cs:345
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.ServerDir
const string ServerDir
The OD server directory name.
Definition: OpenDreamInstaller.cs:34
+
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.DownloadVersion
override async ValueTask< IEngineInstallationData > DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
Download a given engine version . A ValueTask<TResult> resulting in the IEngineInstallationData for t...
Definition: OpenDreamInstaller.cs:136
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.CreateInstallation
override IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
Creates an IEngineInstallation for a given version . The IEngineInstallation.
Definition: OpenDreamInstaller.cs:121
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.CleanCache
override Task CleanCache(CancellationToken cancellationToken)
Attempts to cleans the engine's cache folder for the system. A Task representing the running operatio...
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.OpenDreamInstaller
OpenDreamInstaller(IIOManager ioManager, ILogger< OpenDreamInstaller > logger, IPlatformIdentifier platformIdentifier, IProcessExecutor processExecutor, IRepositoryManager repositoryManager, IAsyncDelayer asyncDelayer, IAbstractHttpClientFactory httpClientFactory, IOptions< GeneralConfiguration > generalConfigurationOptions, IOptions< SessionConfiguration > sessionConfigurationOptions)
Initializes a new instance of the OpenDreamInstaller class.
Definition: OpenDreamInstaller.cs:96
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.InstallationCompilerDirectory
const string InstallationCompilerDirectory
The name of the subdirectory in an installation's BinDir used to store the compiler binaries.
Definition: OpenDreamInstaller.cs:39
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.InstallationSourceSubDirectory
const string InstallationSourceSubDirectory
The name of the subdirectory used for the RepositoryEngineInstallationData's copy.
Definition: OpenDreamInstaller.cs:44
-
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.UpgradeInstallation
override ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
Does actions necessary to get upgrade a version installed by a previous version of TGS....
Definition: OpenDreamInstaller.cs:320
+
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.UpgradeInstallation
override ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken)
Does actions necessary to get upgrade a version installed by a previous version of TGS....
Definition: OpenDreamInstaller.cs:337
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.asyncDelayer
readonly IAsyncDelayer asyncDelayer
The IAsyncDelayer for the OpenDreamInstaller.
Definition: OpenDreamInstaller.cs:77
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.HandleExtremelyLongPathOperation
virtual ValueTask HandleExtremelyLongPathOperation(Func< string, ValueTask > shortenedPathOperation, string originalPath, CancellationToken cancellationToken)
Perform an operation on a very long path.
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.BinDir
const string BinDir
The bin directory name.
Definition: OpenDreamInstaller.cs:29
@@ -419,16 +436,20 @@ $(function() {
Tgstation.Server.Host.Configuration.SessionConfiguration.LowPriorityDeploymentProcesses
bool LowPriorityDeploymentProcesses
If the deployment DreamMaker and DreamDaemon instances are set to be below normal priority processes.
Definition: SessionConfiguration.cs:26
Tgstation.Server.Host.IO.ResolvingIOManager
An IIOManager that resolve relative paths from another IIOManager to a subdirectory of that.
Definition: ResolvingIOManager.cs:10
Tgstation.Server.Host.Jobs.JobException
Operation exceptions thrown from the context of a Models.Job.
Definition: JobException.cs:11
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:100
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:176
Tgstation.Server.Host.System.DotnetHelper
Helper methods for working with the dotnet executable.
Definition: DotnetHelper.cs:14
Tgstation.Server.Host.System.DotnetHelper.GetDotnetPath
static async ValueTask< string?> GetDotnetPath(IPlatformIdentifier platformIdentifier, IIOManager ioManager, CancellationToken cancellationToken)
Locate a dotnet executable to use.
Definition: DotnetHelper.cs:22
Tgstation.Server.Host.System.ProcessExecutor
Definition: ProcessExecutor.cs:19
Tgstation.Server.Host.System.ProcessExecutor.LaunchProcess
async ValueTask< IProcess > LaunchProcess(string fileName, string workingDirectory, string arguments, CancellationToken cancellationToken, IReadOnlyDictionary< string, string >? environment, string? fileRedirect, bool readStandardHandles, bool noShellExecute)
Launch a IProcess. A ValueTask<TResult> resulting in the new IProcess.
Definition: ProcessExecutor.cs:108
Tgstation.Server.Common.Http.IAbstractHttpClientFactory
Creates IHttpClients.
Definition: IAbstractHttpClientFactory.cs:7
Tgstation.Server.Host.Components.Engine.IEngineInstallation
Represents a BYOND installation.
Definition: IEngineInstallation.cs:18
+
Tgstation.Server.Host.Components.Repository.IRepository
Represents an on-disk git repository.
Definition: IRepository.cs:14
+
Tgstation.Server.Host.Components.Repository.IRepository.CommittishIsParent
Task< bool > CommittishIsParent(string committish, CancellationToken cancellationToken)
Check if a given committish is a parent of the current Head.
+
Tgstation.Server.Host.Components.Repository.IRepository.CheckoutObject
ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Checks out a given committish .
+
Tgstation.Server.Host.Components.Repository.IRepository.FetchOrigin
ValueTask FetchOrigin(JobProgressReporter progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Fetch commits from the origin repository.
Tgstation.Server.Host.Components.Repository.IRepositoryManager
Factory for creating and loading IRepositorys.
Definition: IRepositoryManager.cs:13
-
Tgstation.Server.Host.Components.Repository.IRepositoryManager.CloneRepository
ValueTask< IRepository?> CloneRepository(Uri url, string? initialBranch, string? username, string? password, JobProgressReporter? progressReporter, bool recurseSubmodules, CancellationToken cancellationToken)
Clone the repository at url .
+
Tgstation.Server.Host.Components.Repository.IRepositoryManager.CloneRepository
ValueTask< IRepository?> CloneRepository(Uri url, string? initialBranch, string? username, string? password, JobProgressReporter progressReporter, bool recurseSubmodules, CancellationToken cancellationToken)
Clone the repository at url .
Tgstation.Server.Host.Components.Repository.IRepositoryManager.LoadRepository
ValueTask< IRepository?> LoadRepository(CancellationToken cancellationToken)
Attempt to load the IRepository from the default location.
Tgstation.Server.Host.IO.IIOManager
Interface for using filesystems.
Definition: IIOManager.cs:13
Tgstation.Server.Host.IO.IIOManager.GetFiles
Task< IReadOnlyList< string > > GetFiles(string path, CancellationToken cancellationToken)
Returns full file names in a given path .
diff --git a/_process_8cs_source.html b/_process_8cs_source.html index cc87b08400..b35b91c011 100644 --- a/_process_8cs_source.html +++ b/_process_8cs_source.html @@ -97,231 +97,245 @@ $(function() {
21
23 public Task<int?> Lifetime { get; }
24
-
26 public long MemoryUsage => handle.VirtualMemorySize64;
-
27
-
31 readonly IProcessFeatures processFeatures;
-
32
-
36 readonly ILogger<Process> logger;
-
37
-
41 readonly global::System.Diagnostics.Process handle;
-
42
-
46 readonly CancellationTokenSource cancellationTokenSource;
-
47
-
52 readonly SafeProcessHandle safeHandle;
-
53
-
57 readonly Task<string?>? readTask;
-
58
-
62 volatile int disposed;
-
63
-
73 public Process(
-
74 IProcessFeatures processFeatures,
-
75 global::System.Diagnostics.Process handle,
-
76 CancellationTokenSource? readerCts,
-
77 Task<string?>? readTask,
-
78 ILogger<Process> logger,
-
79 bool preExisting)
-
80 {
-
81 this.handle = handle ?? throw new ArgumentNullException(nameof(handle));
-
82
-
83 // Do this fast because the runtime will bitch if we try to access it after it ends
-
84 safeHandle = handle.SafeHandle;
-
85 Id = handle.Id;
-
86
-
87 cancellationTokenSource = readerCts ?? new CancellationTokenSource();
-
88
-
89 this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures));
-
90
-
91 this.readTask = readTask;
-
92
-
93 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
-
94
-
95 Lifetime = WrapLifetimeTask();
+
26 public long? MemoryUsage
+
27 {
+
28 get
+
29 {
+
30 try
+
31 {
+
32 return handle.VirtualMemorySize64;
+
33 }
+
34 catch (Exception ex)
+
35 {
+
36 logger.LogWarning(ex, "Failed to get PID {pid}'s memory usage!", Id);
+
37 return null;
+
38 }
+
39 }
+
40 }
+
41
+
45 readonly IProcessFeatures processFeatures;
+
46
+
50 readonly ILogger<Process> logger;
+
51
+
55 readonly global::System.Diagnostics.Process handle;
+
56
+
60 readonly CancellationTokenSource cancellationTokenSource;
+
61
+
66 readonly SafeProcessHandle safeHandle;
+
67
+
71 readonly Task<string?>? readTask;
+
72
+
76 volatile int disposed;
+
77
+
87 public Process(
+
88 IProcessFeatures processFeatures,
+
89 global::System.Diagnostics.Process handle,
+
90 CancellationTokenSource? readerCts,
+
91 Task<string?>? readTask,
+
92 ILogger<Process> logger,
+
93 bool preExisting)
+
94 {
+
95 this.handle = handle ?? throw new ArgumentNullException(nameof(handle));
96
-
97 if (preExisting)
-
98 {
-
99 Startup = Task.CompletedTask;
-
100 return;
-
101 }
+
97 // Do this fast because the runtime will bitch if we try to access it after it ends
+
98 safeHandle = handle.SafeHandle;
+
99 Id = handle.Id;
+
100
+
101 cancellationTokenSource = readerCts ?? new CancellationTokenSource();
102
-
103 Startup = Task.Factory.StartNew(
-
104 () =>
-
105 {
-
106 try
-
107 {
-
108 handle.WaitForInputIdle();
-
109 }
-
110 catch (Exception ex)
-
111 {
-
112 logger.LogTrace(ex, "WaitForInputIdle() failed, this is normal.");
-
113 }
-
114 },
-
115 CancellationToken.None, // DCT: None available
-
116 DefaultIOManager.BlockingTaskCreationOptions,
-
117 TaskScheduler.Current);
-
118
-
119 logger.LogTrace("Created process ID: {pid}", Id);
-
120 }
-
121
-
123 public async ValueTask DisposeAsync()
-
124 {
-
125 if (Interlocked.Exchange(ref disposed, 1) != 0)
-
126 return;
-
127
-
128 logger.LogTrace("Disposing PID {pid}...", Id);
-
129 cancellationTokenSource.Cancel();
-
130 cancellationTokenSource.Dispose();
-
131 if (readTask != null)
-
132 await readTask;
-
133
-
134 await Lifetime;
+
103 this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures));
+
104
+
105 this.readTask = readTask;
+
106
+
107 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+
108
+
109 Lifetime = WrapLifetimeTask();
+
110
+
111 if (preExisting)
+
112 {
+
113 Startup = Task.CompletedTask;
+
114 return;
+
115 }
+
116
+
117 Startup = Task.Factory.StartNew(
+
118 () =>
+
119 {
+
120 try
+
121 {
+
122 handle.WaitForInputIdle();
+
123 }
+
124 catch (Exception ex)
+
125 {
+
126 logger.LogTrace(ex, "WaitForInputIdle() failed, this is normal.");
+
127 }
+
128 },
+
129 CancellationToken.None, // DCT: None available
+
130 DefaultIOManager.BlockingTaskCreationOptions,
+
131 TaskScheduler.Current);
+
132
+
133 logger.LogTrace("Created process ID: {pid}", Id);
+
134 }
135
-
136 safeHandle.Dispose();
-
137 handle.Dispose();
-
138 }
-
139
-
141 public Task<string?> GetCombinedOutput(CancellationToken cancellationToken)
-
142 {
-
143 if (readTask == null)
-
144 throw new InvalidOperationException("Output/Error stream reading was not enabled!");
-
145
-
146 return readTask.WaitAsync(cancellationToken);
-
147 }
-
148
-
150 public void Terminate()
-
151 {
-
152 CheckDisposed();
-
153 if (handle.HasExited)
-
154 {
-
155 logger.LogTrace("PID {pid} already exited", Id);
-
156 return;
-
157 }
-
158
-
159 try
-
160 {
-
161 logger.LogTrace("Terminating PID {pid}...", Id);
-
162 handle.Kill();
-
163 if (!handle.WaitForExit(5000))
-
164 logger.LogWarning("WaitForExit() on PID {pid} timed out!", Id);
-
165 }
-
166 catch (Exception e)
-
167 {
-
168 logger.LogDebug(e, "PID {pid} termination exception!", Id);
-
169 }
-
170 }
-
171
-
173 public void AdjustPriority(bool higher)
-
174 {
-
175 CheckDisposed();
-
176 var targetPriority = higher ? ProcessPriorityClass.AboveNormal : ProcessPriorityClass.BelowNormal;
-
177 try
-
178 {
-
179 handle.PriorityClass = targetPriority;
-
180 logger.LogTrace("Set PID {pid} to {targetPriority} priority", Id, targetPriority);
-
181 }
-
182 catch (Exception ex)
-
183 {
-
184 logger.LogWarning(ex, "Unable to set priority for PID {id} to {targetPriority}!", Id, targetPriority);
-
185 }
-
186 }
-
187
-
189 public void SuspendProcess()
-
190 {
-
191 CheckDisposed();
-
192 try
-
193 {
-
194 processFeatures.SuspendProcess(handle);
-
195 logger.LogTrace("Suspended PID {pid}", Id);
-
196 }
-
197 catch (Exception e)
-
198 {
-
199 logger.LogError(e, "Failed to suspend PID {pid}!", Id);
-
200 throw;
-
201 }
-
202 }
-
203
-
205 public void ResumeProcess()
-
206 {
-
207 CheckDisposed();
-
208 try
-
209 {
-
210 processFeatures.ResumeProcess(handle);
-
211 logger.LogTrace("Resumed PID {pid}", Id);
-
212 }
-
213 catch (Exception e)
-
214 {
-
215 logger.LogError(e, "Failed to resume PID {pid}!", Id);
-
216 throw;
-
217 }
-
218 }
-
219
-
221 public string GetExecutingUsername()
-
222 {
-
223 CheckDisposed();
-
224 var result = processFeatures.GetExecutingUsername(handle);
-
225 logger.LogTrace("PID {pid} Username: {username}", Id, result);
-
226 return result;
-
227 }
-
228
-
230 public ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
-
231 {
-
232 ArgumentNullException.ThrowIfNull(outputFile);
-
233 CheckDisposed();
-
234
-
235 logger.LogTrace("Dumping PID {pid} to {dumpFilePath}...", Id, outputFile);
-
236 return processFeatures.CreateDump(handle, outputFile, minidump, cancellationToken);
-
237 }
-
238
-
243 async Task<int?> WrapLifetimeTask()
-
244 {
-
245 bool hasExited;
-
246 try
-
247 {
-
248 await handle.WaitForExitAsync(cancellationTokenSource.Token);
-
249 hasExited = true;
-
250 }
-
251 catch (OperationCanceledException ex)
-
252 {
-
253 logger.LogTrace(ex, "Process lifetime task cancelled!");
-
254 hasExited = handle.HasExited;
-
255 }
-
256
-
257 if (!hasExited)
-
258 return null;
-
259
-
260 var exitCode = handle.ExitCode;
-
261 logger.LogTrace("PID {pid} exited with code {exitCode}", Id, exitCode);
-
262 return exitCode;
-
263 }
-
264
-
268 void CheckDisposed() => ObjectDisposedException.ThrowIf(disposed != 0, this);
-
269 }
-
270}
+
137 public async ValueTask DisposeAsync()
+
138 {
+
139 if (Interlocked.Exchange(ref disposed, 1) != 0)
+
140 return;
+
141
+
142 logger.LogTrace("Disposing PID {pid}...", Id);
+
143 cancellationTokenSource.Cancel();
+
144 cancellationTokenSource.Dispose();
+
145 if (readTask != null)
+
146 await readTask;
+
147
+
148 await Lifetime;
+
149
+
150 safeHandle.Dispose();
+
151 handle.Dispose();
+
152 }
+
153
+
155 public Task<string?> GetCombinedOutput(CancellationToken cancellationToken)
+
156 {
+
157 if (readTask == null)
+
158 throw new InvalidOperationException("Output/Error stream reading was not enabled!");
+
159
+
160 return readTask.WaitAsync(cancellationToken);
+
161 }
+
162
+
164 public void Terminate()
+
165 {
+
166 CheckDisposed();
+
167 if (handle.HasExited)
+
168 {
+
169 logger.LogTrace("PID {pid} already exited", Id);
+
170 return;
+
171 }
+
172
+
173 try
+
174 {
+
175 logger.LogTrace("Terminating PID {pid}...", Id);
+
176 handle.Kill();
+
177 if (!handle.WaitForExit(5000))
+
178 logger.LogWarning("WaitForExit() on PID {pid} timed out!", Id);
+
179 }
+
180 catch (Exception e)
+
181 {
+
182 logger.LogDebug(e, "PID {pid} termination exception!", Id);
+
183 }
+
184 }
+
185
+
187 public void AdjustPriority(bool higher)
+
188 {
+
189 CheckDisposed();
+
190 var targetPriority = higher ? ProcessPriorityClass.AboveNormal : ProcessPriorityClass.BelowNormal;
+
191 try
+
192 {
+
193 handle.PriorityClass = targetPriority;
+
194 logger.LogTrace("Set PID {pid} to {targetPriority} priority", Id, targetPriority);
+
195 }
+
196 catch (Exception ex)
+
197 {
+
198 logger.LogWarning(ex, "Unable to set priority for PID {id} to {targetPriority}!", Id, targetPriority);
+
199 }
+
200 }
+
201
+
203 public void SuspendProcess()
+
204 {
+
205 CheckDisposed();
+
206 try
+
207 {
+
208 processFeatures.SuspendProcess(handle);
+
209 logger.LogTrace("Suspended PID {pid}", Id);
+
210 }
+
211 catch (Exception e)
+
212 {
+
213 logger.LogError(e, "Failed to suspend PID {pid}!", Id);
+
214 throw;
+
215 }
+
216 }
+
217
+
219 public void ResumeProcess()
+
220 {
+
221 CheckDisposed();
+
222 try
+
223 {
+
224 processFeatures.ResumeProcess(handle);
+
225 logger.LogTrace("Resumed PID {pid}", Id);
+
226 }
+
227 catch (Exception e)
+
228 {
+
229 logger.LogError(e, "Failed to resume PID {pid}!", Id);
+
230 throw;
+
231 }
+
232 }
+
233
+
235 public string GetExecutingUsername()
+
236 {
+
237 CheckDisposed();
+
238 var result = processFeatures.GetExecutingUsername(handle);
+
239 logger.LogTrace("PID {pid} Username: {username}", Id, result);
+
240 return result;
+
241 }
+
242
+
244 public ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
+
245 {
+
246 ArgumentNullException.ThrowIfNull(outputFile);
+
247 CheckDisposed();
+
248
+
249 logger.LogTrace("Dumping PID {pid} to {dumpFilePath}...", Id, outputFile);
+
250 return processFeatures.CreateDump(handle, outputFile, minidump, cancellationToken);
+
251 }
+
252
+
257 async Task<int?> WrapLifetimeTask()
+
258 {
+
259 bool hasExited;
+
260 try
+
261 {
+
262 await handle.WaitForExitAsync(cancellationTokenSource.Token);
+
263 hasExited = true;
+
264 }
+
265 catch (OperationCanceledException ex)
+
266 {
+
267 logger.LogTrace(ex, "Process lifetime task cancelled!");
+
268 hasExited = handle.HasExited;
+
269 }
+
270
+
271 if (!hasExited)
+
272 return null;
+
273
+
274 var exitCode = handle.ExitCode;
+
275 logger.LogTrace("PID {pid} exited with code {exitCode}", Id, exitCode);
+
276 return exitCode;
+
277 }
+
278
+
282 void CheckDisposed() => ObjectDisposedException.ThrowIf(disposed != 0, this);
+
283 }
+
284}
Exception
Tgstation.Server.Host.IO.DefaultIOManager
IIOManager that resolves paths to Environment.CurrentDirectory.
Definition: DefaultIOManager.cs:17
Tgstation.Server.Host.IO.DefaultIOManager.BlockingTaskCreationOptions
const TaskCreationOptions BlockingTaskCreationOptions
The TaskCreationOptions used to spawn Tasks for potentially long running, blocking operations.
Definition: DefaultIOManager.cs:31
Tgstation.Server.Host.System.Process
Definition: Process.cs:15
-
Tgstation.Server.Host.System.Process.Process
Process(IProcessFeatures processFeatures, global::System.Diagnostics.Process handle, CancellationTokenSource? readerCts, Task< string?>? readTask, ILogger< Process > logger, bool preExisting)
Initializes a new instance of the Process class.
Definition: Process.cs:73
+
Tgstation.Server.Host.System.Process.Process
Process(IProcessFeatures processFeatures, global::System.Diagnostics.Process handle, CancellationTokenSource? readerCts, Task< string?>? readTask, ILogger< Process > logger, bool preExisting)
Initializes a new instance of the Process class.
Definition: Process.cs:87
Tgstation.Server.Host.System.Process.CheckDisposed
void CheckDisposed()
Throws an ObjectDisposedException if a method of the Process was called after DisposeAsync.
-
Tgstation.Server.Host.System.Process.DisposeAsync
async ValueTask DisposeAsync()
Definition: Process.cs:123
+
Tgstation.Server.Host.System.Process.DisposeAsync
async ValueTask DisposeAsync()
Definition: Process.cs:137
Tgstation.Server.Host.System.Process.Id
int Id
The IProcess' ID.
Definition: Process.cs:17
-
Tgstation.Server.Host.System.Process.handle
readonly global::System.Diagnostics.Process handle
The global::System.Diagnostics.Process object.
Definition: Process.cs:41
+
Tgstation.Server.Host.System.Process.handle
readonly global::System.Diagnostics.Process handle
The global::System.Diagnostics.Process object.
Definition: Process.cs:55
Tgstation.Server.Host.System.Process.Lifetime
Task< int?> Lifetime
The Task<TResult> resulting in the exit code of the process or null if the process was detached.
Definition: Process.cs:23
-
Tgstation.Server.Host.System.Process.GetCombinedOutput
Task< string?> GetCombinedOutput(CancellationToken cancellationToken)
Get the stderr and stdout output of the IProcess. A Task<TResult> resulting in the stderr and stdout ...
Definition: Process.cs:141
-
Tgstation.Server.Host.System.Process.AdjustPriority
void AdjustPriority(bool higher)
Set's the owned global::System.Diagnostics.Process.PriorityClass to a non-normal value.
Definition: Process.cs:173
-
Tgstation.Server.Host.System.Process.CreateDump
ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
Create a dump file of the process. A ValueTask representing the running operation.
Definition: Process.cs:230
-
Tgstation.Server.Host.System.Process.disposed
volatile int disposed
If the Process was disposed.
Definition: Process.cs:62
-
Tgstation.Server.Host.System.Process.Terminate
void Terminate()
Asycnhronously terminates the process. To ensure the IProcess has ended, use the IProcessBase....
Definition: Process.cs:150
-
Tgstation.Server.Host.System.Process.logger
readonly ILogger< Process > logger
The ILogger for the Process.
Definition: Process.cs:36
-
Tgstation.Server.Host.System.Process.SuspendProcess
void SuspendProcess()
Suspends the process.
Definition: Process.cs:189
-
Tgstation.Server.Host.System.Process.cancellationTokenSource
readonly CancellationTokenSource cancellationTokenSource
The CancellationTokenSource used to shutdown the readTask and Lifetime.
Definition: Process.cs:46
-
Tgstation.Server.Host.System.Process.GetExecutingUsername
string GetExecutingUsername()
Get the name of the account executing the IProcess. The name of the account executing the IProcess.
Definition: Process.cs:221
-
Tgstation.Server.Host.System.Process.ResumeProcess
void ResumeProcess()
Resumes the process.
Definition: Process.cs:205
-
Tgstation.Server.Host.System.Process.MemoryUsage
long MemoryUsage
Gets the process' memory usage in bytes.
Definition: Process.cs:26
-
Tgstation.Server.Host.System.Process.safeHandle
readonly SafeProcessHandle safeHandle
The global::System.Diagnostics.Process.SafeHandle.
Definition: Process.cs:52
-
Tgstation.Server.Host.System.Process.processFeatures
readonly IProcessFeatures processFeatures
The IProcessFeatures for the Process.
Definition: Process.cs:31
+
Tgstation.Server.Host.System.Process.GetCombinedOutput
Task< string?> GetCombinedOutput(CancellationToken cancellationToken)
Get the stderr and stdout output of the IProcess. A Task<TResult> resulting in the stderr and stdout ...
Definition: Process.cs:155
+
Tgstation.Server.Host.System.Process.AdjustPriority
void AdjustPriority(bool higher)
Set's the owned global::System.Diagnostics.Process.PriorityClass to a non-normal value.
Definition: Process.cs:187
+
Tgstation.Server.Host.System.Process.CreateDump
ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
Create a dump file of the process. A ValueTask representing the running operation.
Definition: Process.cs:244
+
Tgstation.Server.Host.System.Process.disposed
volatile int disposed
If the Process was disposed.
Definition: Process.cs:76
+
Tgstation.Server.Host.System.Process.Terminate
void Terminate()
Asycnhronously terminates the process. To ensure the IProcess has ended, use the IProcessBase....
Definition: Process.cs:164
+
Tgstation.Server.Host.System.Process.logger
readonly ILogger< Process > logger
The ILogger for the Process.
Definition: Process.cs:50
+
Tgstation.Server.Host.System.Process.SuspendProcess
void SuspendProcess()
Suspends the process.
Definition: Process.cs:203
+
Tgstation.Server.Host.System.Process.cancellationTokenSource
readonly CancellationTokenSource cancellationTokenSource
The CancellationTokenSource used to shutdown the readTask and Lifetime.
Definition: Process.cs:60
+
Tgstation.Server.Host.System.Process.GetExecutingUsername
string GetExecutingUsername()
Get the name of the account executing the IProcess. The name of the account executing the IProcess.
Definition: Process.cs:235
+
Tgstation.Server.Host.System.Process.ResumeProcess
void ResumeProcess()
Resumes the process.
Definition: Process.cs:219
+
Tgstation.Server.Host.System.Process.safeHandle
readonly SafeProcessHandle safeHandle
The global::System.Diagnostics.Process.SafeHandle.
Definition: Process.cs:66
+
Tgstation.Server.Host.System.Process.processFeatures
readonly IProcessFeatures processFeatures
The IProcessFeatures for the Process.
Definition: Process.cs:45
Tgstation.Server.Host.System.Process.Startup
Task Startup
The Task representing the time until the IProcess becomes "idle".
Definition: Process.cs:20
-
Tgstation.Server.Host.System.Process.readTask
readonly? Task< string?> readTask
The Task<TResult> resulting in the process' standard output/error text.
Definition: Process.cs:57
-
Tgstation.Server.Host.System.Process.WrapLifetimeTask
async Task< int?> WrapLifetimeTask()
Attaches a log message to the process' exit event.
Definition: Process.cs:243
+
Tgstation.Server.Host.System.Process.MemoryUsage
long? MemoryUsage
Gets the process' memory usage in bytes.
Definition: Process.cs:27
+
Tgstation.Server.Host.System.Process.readTask
readonly? Task< string?> readTask
The Task<TResult> resulting in the process' standard output/error text.
Definition: Process.cs:71
+
Tgstation.Server.Host.System.Process.WrapLifetimeTask
async Task< int?> WrapLifetimeTask()
Attaches a log message to the process' exit event.
Definition: Process.cs:257
Tgstation.Server.Host.System.IProcessFeatures
Abstraction for suspending and resuming processes.
Definition: IProcessFeatures.cs:10
Tgstation.Server.Host.System.IProcessFeatures.GetExecutingUsername
string GetExecutingUsername(global::System.Diagnostics.Process process)
Get the name of the user executing a given process .
Tgstation.Server.Host.System.IProcessFeatures.CreateDump
ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, bool minidump, CancellationToken cancellationToken)
Create a dump file for a given process .
diff --git a/_repository_8cs_source.html b/_repository_8cs_source.html index 200fd52000..65043f69a9 100644 --- a/_repository_8cs_source.html +++ b/_repository_8cs_source.html @@ -240,907 +240,969 @@ $(function() {
232 logger.LogTrace("Fetching refspec {refSpec}...", refSpec);
233
234 var remote = libGitRepo.Network.Remotes.First();
-
235 commands.Fetch(
-
236 libGitRepo,
-
237 refSpecList,
-
238 remote,
-
239 new FetchOptions().Hydrate(
-
240 logger,
-
241 progressReporter.CreateSection($"Fetch {refSpec}", progressFactor),
-
242 credentialsProvider.GenerateCredentialsHandler(username, password),
-
243 cancellationToken),
-
244 logMessage);
-
245 }
-
246 catch (UserCancelledException ex)
-
247 {
-
248 logger.LogTrace(ex, "Suppressing fetch cancel exception");
-
249 }
-
250 catch (LibGit2SharpException ex)
-
251 {
-
252 credentialsProvider.CheckBadCredentialsException(ex);
-
253 }
-
254
-
255 cancellationToken.ThrowIfCancellationRequested();
-
256
-
257 libGitRepo.RemoveUntrackedFiles();
-
258
-
259 cancellationToken.ThrowIfCancellationRequested();
-
260
-
261 var objectName = testMergeParameters.TargetCommitSha ?? localBranchName;
-
262 var gitObject = libGitRepo.Lookup(objectName) ?? throw new JobException($"Could not find object to merge: {objectName}");
-
263
-
264 testMergeParameters.TargetCommitSha = gitObject.Sha;
-
265
-
266 cancellationToken.ThrowIfCancellationRequested();
-
267
-
268 logger.LogTrace("Merging {targetCommitSha} into {currentReference}...", testMergeParameters.TargetCommitSha[..7], Reference);
-
269
-
270 result = libGitRepo.Merge(testMergeParameters.TargetCommitSha, sig, new MergeOptions
-
271 {
-
272 CommitOnSuccess = commitMessage == null,
-
273 FailOnConflict = false, // Needed to get conflicting files
-
274 FastForwardStrategy = FastForwardStrategy.NoFastForward,
-
275 SkipReuc = true,
-
276 OnCheckoutProgress = CheckoutProgressHandler(
-
277 progressReporter.CreateSection($"Merge {testMergeParameters.TargetCommitSha[..7]}", progressFactor)),
-
278 });
-
279 }
-
280 finally
-
281 {
-
282 libGitRepo.Branches.Remove(localBranchName);
-
283 }
-
284
-
285 cancellationToken.ThrowIfCancellationRequested();
-
286
-
287 if (result.Status == MergeStatus.Conflicts)
-
288 {
-
289 var repoStatus = libGitRepo.RetrieveStatus();
-
290 conflictedPaths = new List<string>();
-
291 foreach (var file in repoStatus)
-
292 if (file.State == FileStatus.Conflicted)
-
293 conflictedPaths.Add(file.FilePath);
-
294
-
295 var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha;
-
296 logger.LogDebug("Merge conflict, aborting and reverting to {revertTarget}", revertTo);
-
297 progressReporter.ReportProgress(0);
-
298 RawCheckout(revertTo, false, progressReporter.CreateSection("Hard Reset to {revertTo}", 1.0), cancellationToken);
-
299 cancellationToken.ThrowIfCancellationRequested();
-
300 }
-
301
-
302 libGitRepo.RemoveUntrackedFiles();
-
303 },
-
304 cancellationToken,
-
305 DefaultIOManager.BlockingTaskCreationOptions,
-
306 TaskScheduler.Current);
-
307
-
308 if (result!.Status == MergeStatus.Conflicts)
-
309 {
-
310 var arguments = new List<string>
-
311 {
-
312 originalCommit.Tip.Sha,
-
313 testMergeParameters.TargetCommitSha!,
-
314 originalCommit.FriendlyName ?? UnknownReference,
-
315 testMergeBranchName,
-
316 };
-
317
-
318 arguments.AddRange(conflictedPaths!);
+
235 using var fetchReporter = progressReporter.CreateSection($"Fetch {refSpec}", progressFactor);
+
236 commands.Fetch(
+
237 libGitRepo,
+
238 refSpecList,
+
239 remote,
+
240 new FetchOptions().Hydrate(
+
241 logger,
+
242 fetchReporter,
+
243 credentialsProvider.GenerateCredentialsHandler(username, password),
+
244 cancellationToken),
+
245 logMessage);
+
246 }
+
247 catch (UserCancelledException ex)
+
248 {
+
249 logger.LogTrace(ex, "Suppressing fetch cancel exception");
+
250 }
+
251 catch (LibGit2SharpException ex)
+
252 {
+
253 credentialsProvider.CheckBadCredentialsException(ex);
+
254 }
+
255
+
256 cancellationToken.ThrowIfCancellationRequested();
+
257
+
258 libGitRepo.RemoveUntrackedFiles();
+
259
+
260 cancellationToken.ThrowIfCancellationRequested();
+
261
+
262 var objectName = testMergeParameters.TargetCommitSha ?? localBranchName;
+
263 var gitObject = libGitRepo.Lookup(objectName) ?? throw new JobException($"Could not find object to merge: {objectName}");
+
264
+
265 testMergeParameters.TargetCommitSha = gitObject.Sha;
+
266
+
267 cancellationToken.ThrowIfCancellationRequested();
+
268
+
269 logger.LogTrace("Merging {targetCommitSha} into {currentReference}...", testMergeParameters.TargetCommitSha[..7], Reference);
+
270
+
271 using var mergeReporter = progressReporter.CreateSection($"Merge {testMergeParameters.TargetCommitSha[..7]}", progressFactor);
+
272 result = libGitRepo.Merge(testMergeParameters.TargetCommitSha, sig, new MergeOptions
+
273 {
+
274 CommitOnSuccess = commitMessage == null,
+
275 FailOnConflict = false, // Needed to get conflicting files
+
276 FastForwardStrategy = FastForwardStrategy.NoFastForward,
+
277 SkipReuc = true,
+
278 OnCheckoutProgress = CheckoutProgressHandler(mergeReporter),
+
279 });
+
280 }
+
281 finally
+
282 {
+
283 libGitRepo.Branches.Remove(localBranchName);
+
284 }
+
285
+
286 cancellationToken.ThrowIfCancellationRequested();
+
287
+
288 if (result.Status == MergeStatus.Conflicts)
+
289 {
+
290 var repoStatus = libGitRepo.RetrieveStatus();
+
291 conflictedPaths = new List<string>();
+
292 foreach (var file in repoStatus)
+
293 if (file.State == FileStatus.Conflicted)
+
294 conflictedPaths.Add(file.FilePath);
+
295
+
296 var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha;
+
297 logger.LogDebug("Merge conflict, aborting and reverting to {revertTarget}", revertTo);
+
298 progressReporter.ReportProgress(0);
+
299 using var revertReporter = progressReporter.CreateSection("Hard Reset to {revertTo}", 1.0);
+
300 RawCheckout(revertTo, false, revertReporter, cancellationToken);
+
301 cancellationToken.ThrowIfCancellationRequested();
+
302 }
+
303
+
304 libGitRepo.RemoveUntrackedFiles();
+
305 },
+
306 cancellationToken,
+
307 DefaultIOManager.BlockingTaskCreationOptions,
+
308 TaskScheduler.Current);
+
309
+
310 if (result!.Status == MergeStatus.Conflicts)
+
311 {
+
312 var arguments = new List<string>
+
313 {
+
314 originalCommit.Tip.Sha,
+
315 testMergeParameters.TargetCommitSha!,
+
316 originalCommit.FriendlyName ?? UnknownReference,
+
317 testMergeBranchName,
+
318 };
319
-
320 await eventConsumer.HandleEvent(
-
321 EventType.RepoMergeConflict,
-
322 arguments,
-
323 false,
-
324 cancellationToken);
-
325 return new TestMergeResult
-
326 {
-
327 Status = result.Status,
-
328 ConflictingFiles = conflictedPaths,
-
329 };
-
330 }
-
331
-
332 if (result.Status != MergeStatus.UpToDate)
-
333 {
-
334 logger.LogTrace("Committing merge: \"{commitMessage}\"...", commitMessage);
-
335 await Task.Factory.StartNew(
-
336 () => libGitRepo.Commit(commitMessage, sig, sig, new CommitOptions
-
337 {
-
338 PrettifyMessage = true,
-
339 }),
-
340 cancellationToken,
-
341 DefaultIOManager.BlockingTaskCreationOptions,
-
342 TaskScheduler.Current);
-
343
-
344 if (updateSubmodules)
-
345 {
-
346 await UpdateSubmodules(
-
347 progressReporter.CreateSection("Update Submodules", progressFactor),
-
348 username,
-
349 password,
-
350 false,
-
351 cancellationToken);
-
352 }
-
353 }
-
354
-
355 await eventConsumer.HandleEvent(
-
356 EventType.RepoAddTestMerge,
-
357 new List<string?>
-
358 {
-
359 testMergeParameters.Number.ToString(CultureInfo.InvariantCulture),
-
360 testMergeParameters.TargetCommitSha!,
-
361 testMergeParameters.Comment,
-
362 },
-
363 false,
-
364 cancellationToken);
-
365
-
366 return new TestMergeResult
-
367 {
-
368 Status = result.Status,
-
369 };
-
370 }
-
371#pragma warning restore CA1506
-
372
-
374 public async ValueTask CheckoutObject(
-
375 string committish,
-
376 string? username,
-
377 string? password,
-
378 bool updateSubmodules,
-
379 bool moveCurrentReference,
-
380 JobProgressReporter? progressReporter,
-
381 CancellationToken cancellationToken)
-
382 {
-
383 ArgumentNullException.ThrowIfNull(committish);
-
384
-
385 logger.LogDebug("Checkout object: {committish}...", committish);
-
386 await eventConsumer.HandleEvent(EventType.RepoCheckout, new List<string> { committish, moveCurrentReference.ToString() }, false, cancellationToken);
-
387 await Task.Factory.StartNew(
-
388 () =>
-
389 {
-
390 libGitRepo.RemoveUntrackedFiles();
-
391 RawCheckout(
-
392 committish,
-
393 moveCurrentReference,
-
394 progressReporter?.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0),
-
395 cancellationToken);
-
396 },
-
397 cancellationToken,
-
398 DefaultIOManager.BlockingTaskCreationOptions,
-
399 TaskScheduler.Current);
-
400
-
401 if (updateSubmodules)
-
402 await UpdateSubmodules(
-
403 progressReporter?.CreateSection(null, 1.0 / 3),
-
404 username,
-
405 password,
-
406 false,
-
407 cancellationToken);
-
408 }
-
409
-
411 public async ValueTask FetchOrigin(
-
412 JobProgressReporter? progressReporter,
-
413 string? username,
-
414 string? password,
-
415 bool deploymentPipeline,
-
416 CancellationToken cancellationToken)
-
417 {
-
418 logger.LogDebug("Fetch origin...");
-
419 await eventConsumer.HandleEvent(EventType.RepoFetch, Enumerable.Empty<string>(), deploymentPipeline, cancellationToken);
-
420 await Task.Factory.StartNew(
-
421 () =>
-
422 {
-
423 var remote = libGitRepo.Network.Remotes.First();
-
424 try
-
425 {
-
426 var fetchOptions = new FetchOptions
-
427 {
-
428 Prune = true,
-
429 TagFetchMode = TagFetchMode.All,
-
430 }.Hydrate(
-
431 logger,
-
432 progressReporter?.CreateSection("Fetch Origin", 1.0),
-
433 credentialsProvider.GenerateCredentialsHandler(username, password),
-
434 cancellationToken);
-
435
-
436 commands.Fetch(
-
437 libGitRepo,
-
438 remote
-
439 .FetchRefSpecs
-
440 .Select(x => x.Specification),
-
441 remote,
-
442 fetchOptions,
-
443 "Fetch origin commits");
-
444 }
-
445 catch (UserCancelledException)
-
446 {
-
447 cancellationToken.ThrowIfCancellationRequested();
-
448 }
-
449 catch (LibGit2SharpException ex)
-
450 {
-
451 credentialsProvider.CheckBadCredentialsException(ex);
+
320 arguments.AddRange(conflictedPaths!);
+
321
+
322 await eventConsumer.HandleEvent(
+
323 EventType.RepoMergeConflict,
+
324 arguments,
+
325 false,
+
326 cancellationToken);
+
327 return new TestMergeResult
+
328 {
+
329 Status = result.Status,
+
330 ConflictingFiles = conflictedPaths,
+
331 };
+
332 }
+
333
+
334 if (result.Status != MergeStatus.UpToDate)
+
335 {
+
336 logger.LogTrace("Committing merge: \"{commitMessage}\"...", commitMessage);
+
337 await Task.Factory.StartNew(
+
338 () => libGitRepo.Commit(commitMessage, sig, sig, new CommitOptions
+
339 {
+
340 PrettifyMessage = true,
+
341 }),
+
342 cancellationToken,
+
343 DefaultIOManager.BlockingTaskCreationOptions,
+
344 TaskScheduler.Current);
+
345
+
346 if (updateSubmodules)
+
347 {
+
348 using var progressReporter2 = progressReporter.CreateSection("Update Submodules", progressFactor);
+
349 await UpdateSubmodules(
+
350 progressReporter2,
+
351 username,
+
352 password,
+
353 false,
+
354 cancellationToken);
+
355 }
+
356 }
+
357
+
358 await eventConsumer.HandleEvent(
+
359 EventType.RepoAddTestMerge,
+
360 new List<string?>
+
361 {
+
362 testMergeParameters.Number.ToString(CultureInfo.InvariantCulture),
+
363 testMergeParameters.TargetCommitSha!,
+
364 testMergeParameters.Comment,
+
365 },
+
366 false,
+
367 cancellationToken);
+
368
+
369 return new TestMergeResult
+
370 {
+
371 Status = result.Status,
+
372 };
+
373 }
+
374#pragma warning restore CA1506
+
375
+
377 public async ValueTask CheckoutObject(
+
378 string committish,
+
379 string? username,
+
380 string? password,
+
381 bool updateSubmodules,
+
382 bool moveCurrentReference,
+
383 JobProgressReporter progressReporter,
+
384 CancellationToken cancellationToken)
+
385 {
+
386 ArgumentNullException.ThrowIfNull(committish);
+
387
+
388 logger.LogDebug("Checkout object: {committish}...", committish);
+
389 await eventConsumer.HandleEvent(EventType.RepoCheckout, new List<string> { committish, moveCurrentReference.ToString() }, false, cancellationToken);
+
390 await Task.Factory.StartNew(
+
391 () =>
+
392 {
+
393 libGitRepo.RemoveUntrackedFiles();
+
394 using var progressReporter3 = progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0);
+
395 RawCheckout(
+
396 committish,
+
397 moveCurrentReference,
+
398 progressReporter3,
+
399 cancellationToken);
+
400 },
+
401 cancellationToken,
+
402 DefaultIOManager.BlockingTaskCreationOptions,
+
403 TaskScheduler.Current);
+
404
+
405 if (updateSubmodules)
+
406 {
+
407 using var progressReporter2 = progressReporter.CreateSection(null, 1.0 / 3);
+
408 await UpdateSubmodules(
+
409 progressReporter2,
+
410 username,
+
411 password,
+
412 false,
+
413 cancellationToken);
+
414 }
+
415 }
+
416
+
418 public async ValueTask FetchOrigin(
+
419 JobProgressReporter progressReporter,
+
420 string? username,
+
421 string? password,
+
422 bool deploymentPipeline,
+
423 CancellationToken cancellationToken)
+
424 {
+
425 logger.LogDebug("Fetch origin...");
+
426 await eventConsumer.HandleEvent(EventType.RepoFetch, Enumerable.Empty<string>(), deploymentPipeline, cancellationToken);
+
427 await Task.Factory.StartNew(
+
428 () =>
+
429 {
+
430 var remote = libGitRepo.Network.Remotes.First();
+
431 try
+
432 {
+
433 using var subReporter = progressReporter.CreateSection("Fetch Origin", 1.0);
+
434 var fetchOptions = new FetchOptions
+
435 {
+
436 Prune = true,
+
437 TagFetchMode = TagFetchMode.All,
+
438 }.Hydrate(
+
439 logger,
+
440 subReporter,
+
441 credentialsProvider.GenerateCredentialsHandler(username, password),
+
442 cancellationToken);
+
443
+
444 commands.Fetch(
+
445 libGitRepo,
+
446 remote
+
447 .FetchRefSpecs
+
448 .Select(x => x.Specification),
+
449 remote,
+
450 fetchOptions,
+
451 "Fetch origin commits");
452 }
-
453 },
-
454 cancellationToken,
-
455 DefaultIOManager.BlockingTaskCreationOptions,
-
456 TaskScheduler.Current);
-
457 }
-
458
-
460 public async ValueTask ResetToOrigin(
-
461 JobProgressReporter progressReporter,
-
462 string? username,
-
463 string? password,
-
464 bool updateSubmodules,
-
465 bool deploymentPipeline,
-
466 CancellationToken cancellationToken)
-
467 {
-
468 ArgumentNullException.ThrowIfNull(progressReporter);
-
469 if (!Tracking)
-
470 throw new JobException(ErrorCode.RepoReferenceRequired);
-
471 logger.LogTrace("Reset to origin...");
-
472 var trackedBranch = libGitRepo.Head.TrackedBranch;
-
473 await eventConsumer.HandleEvent(EventType.RepoResetOrigin, new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, deploymentPipeline, cancellationToken);
-
474 await ResetToSha(
-
475 trackedBranch.Tip.Sha,
-
476 progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0),
-
477 cancellationToken);
-
478
-
479 if (updateSubmodules)
-
480 await UpdateSubmodules(
-
481 progressReporter.CreateSection(null, 1.0 / 3),
-
482 username,
-
483 password,
-
484 deploymentPipeline,
-
485 cancellationToken);
-
486 }
-
487
-
489 public Task ResetToSha(string sha, JobProgressReporter progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
-
490 () =>
-
491 {
-
492 ArgumentNullException.ThrowIfNull(sha);
-
493 ArgumentNullException.ThrowIfNull(progressReporter);
-
494
-
495 logger.LogDebug("Reset to sha: {sha}", sha[..7]);
-
496
-
497 libGitRepo.RemoveUntrackedFiles();
-
498 cancellationToken.ThrowIfCancellationRequested();
-
499
-
500 var gitObject = libGitRepo.Lookup(sha, ObjectType.Commit);
-
501 cancellationToken.ThrowIfCancellationRequested();
-
502
-
503 if (gitObject == null)
-
504 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot reset to non-existent SHA: {0}", sha));
-
505
-
506 libGitRepo.Reset(ResetMode.Hard, gitObject.Peel<Commit>(), new CheckoutOptions
-
507 {
-
508 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($"Reset to {gitObject.Sha}", 1.0)),
-
509 });
-
510 },
-
511 cancellationToken,
-
512 DefaultIOManager.BlockingTaskCreationOptions,
-
513 TaskScheduler.Current);
-
514
-
516 public async ValueTask CopyTo(string path, CancellationToken cancellationToken)
-
517 {
-
518 ArgumentNullException.ThrowIfNull(path);
-
519 logger.LogTrace("Copying to {path}...", path);
-
520 await ioManager.CopyDirectory(
-
521 new List<string> { ".git" },
-
522 (src, dest) =>
-
523 {
-
524 if (postWriteHandler.NeedsPostWrite(src))
-
525 postWriteHandler.HandleWrite(dest);
-
526
-
527 return ValueTask.CompletedTask;
-
528 },
-
529 ioManager.ResolvePath(),
-
530 path,
-
531 generalConfiguration.GetCopyDirectoryTaskThrottle(),
-
532 cancellationToken);
-
533 }
-
534
-
536 public Task<string> GetOriginSha(CancellationToken cancellationToken) => Task.Factory.StartNew(
-
537 () =>
-
538 {
-
539 if (!Tracking)
-
540 throw new JobException(ErrorCode.RepoReferenceRequired);
-
541
-
542 cancellationToken.ThrowIfCancellationRequested();
-
543
-
544 return libGitRepo.Head.TrackedBranch.Tip.Sha;
-
545 },
-
546 cancellationToken,
-
547 DefaultIOManager.BlockingTaskCreationOptions,
-
548 TaskScheduler.Current);
-
549
-
551 public async ValueTask<bool?> MergeOrigin(
-
552 JobProgressReporter progressReporter,
-
553 string committerName,
-
554 string committerEmail,
-
555 bool deploymentPipeline,
-
556 CancellationToken cancellationToken)
-
557 {
-
558 ArgumentNullException.ThrowIfNull(progressReporter);
-
559
-
560 MergeResult? result = null;
-
561 Branch? trackedBranch = null;
+
453 catch (UserCancelledException)
+
454 {
+
455 cancellationToken.ThrowIfCancellationRequested();
+
456 }
+
457 catch (LibGit2SharpException ex)
+
458 {
+
459 credentialsProvider.CheckBadCredentialsException(ex);
+
460 }
+
461 },
+
462 cancellationToken,
+
463 DefaultIOManager.BlockingTaskCreationOptions,
+
464 TaskScheduler.Current);
+
465 }
+
466
+
468 public async ValueTask ResetToOrigin(
+
469 JobProgressReporter progressReporter,
+
470 string? username,
+
471 string? password,
+
472 bool updateSubmodules,
+
473 bool deploymentPipeline,
+
474 CancellationToken cancellationToken)
+
475 {
+
476 ArgumentNullException.ThrowIfNull(progressReporter);
+
477 if (!Tracking)
+
478 throw new JobException(ErrorCode.RepoReferenceRequired);
+
479 logger.LogTrace("Reset to origin...");
+
480 var trackedBranch = libGitRepo.Head.TrackedBranch;
+
481 await eventConsumer.HandleEvent(EventType.RepoResetOrigin, new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, deploymentPipeline, cancellationToken);
+
482
+
483 using (var progressReporter2 = progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0))
+
484 await ResetToSha(
+
485 trackedBranch.Tip.Sha,
+
486 progressReporter2,
+
487 cancellationToken);
+
488
+
489 if (updateSubmodules)
+
490 {
+
491 using var progressReporter3 = progressReporter.CreateSection(null, 1.0 / 3);
+
492 await UpdateSubmodules(
+
493 progressReporter3,
+
494 username,
+
495 password,
+
496 deploymentPipeline,
+
497 cancellationToken);
+
498 }
+
499 }
+
500
+
502 public Task ResetToSha(string sha, JobProgressReporter progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
+
503 () =>
+
504 {
+
505 ArgumentNullException.ThrowIfNull(sha);
+
506 ArgumentNullException.ThrowIfNull(progressReporter);
+
507
+
508 logger.LogDebug("Reset to sha: {sha}", sha[..7]);
+
509
+
510 libGitRepo.RemoveUntrackedFiles();
+
511 cancellationToken.ThrowIfCancellationRequested();
+
512
+
513 var gitObject = libGitRepo.Lookup(sha, ObjectType.Commit);
+
514 cancellationToken.ThrowIfCancellationRequested();
+
515
+
516 if (gitObject == null)
+
517 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot reset to non-existent SHA: {0}", sha));
+
518
+
519 libGitRepo.Reset(ResetMode.Hard, gitObject.Peel<Commit>(), new CheckoutOptions
+
520 {
+
521 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($"Reset to {gitObject.Sha}", 1.0)),
+
522 });
+
523 },
+
524 cancellationToken,
+
525 DefaultIOManager.BlockingTaskCreationOptions,
+
526 TaskScheduler.Current);
+
527
+
529 public async ValueTask CopyTo(string path, CancellationToken cancellationToken)
+
530 {
+
531 ArgumentNullException.ThrowIfNull(path);
+
532 logger.LogTrace("Copying to {path}...", path);
+
533 await ioManager.CopyDirectory(
+
534 new List<string> { ".git" },
+
535 (src, dest) =>
+
536 {
+
537 if (postWriteHandler.NeedsPostWrite(src))
+
538 postWriteHandler.HandleWrite(dest);
+
539
+
540 return ValueTask.CompletedTask;
+
541 },
+
542 ioManager.ResolvePath(),
+
543 path,
+
544 generalConfiguration.GetCopyDirectoryTaskThrottle(),
+
545 cancellationToken);
+
546 }
+
547
+
549 public Task<string> GetOriginSha(CancellationToken cancellationToken) => Task.Factory.StartNew(
+
550 () =>
+
551 {
+
552 if (!Tracking)
+
553 throw new JobException(ErrorCode.RepoReferenceRequired);
+
554
+
555 cancellationToken.ThrowIfCancellationRequested();
+
556
+
557 return libGitRepo.Head.TrackedBranch.Tip.Sha;
+
558 },
+
559 cancellationToken,
+
560 DefaultIOManager.BlockingTaskCreationOptions,
+
561 TaskScheduler.Current);
562
-
563 var oldHead = libGitRepo.Head;
-
564 var oldTip = oldHead.Tip;
-
565
-
566 await Task.Factory.StartNew(
-
567 () =>
-
568 {
-
569 if (!Tracking)
-
570 throw new JobException(ErrorCode.RepoReferenceRequired);
-
571
-
572 libGitRepo.RemoveUntrackedFiles();
-
573
-
574 cancellationToken.ThrowIfCancellationRequested();
+
564 public async ValueTask<bool?> MergeOrigin(
+
565 JobProgressReporter progressReporter,
+
566 string committerName,
+
567 string committerEmail,
+
568 bool deploymentPipeline,
+
569 CancellationToken cancellationToken)
+
570 {
+
571 ArgumentNullException.ThrowIfNull(progressReporter);
+
572
+
573 MergeResult? result = null;
+
574 Branch? trackedBranch = null;
575
-
576 trackedBranch = libGitRepo.Head.TrackedBranch;
-
577 logger.LogDebug(
-
578 "Merge origin/{trackedBranch}: <{committerName} ({committerEmail})>",
-
579 trackedBranch.FriendlyName,
-
580 committerName,
-
581 committerEmail);
-
582 result = libGitRepo.Merge(trackedBranch, new Signature(committerName, committerEmail, DateTimeOffset.UtcNow), new MergeOptions
-
583 {
-
584 CommitOnSuccess = true,
-
585 FailOnConflict = true,
-
586 FastForwardStrategy = FastForwardStrategy.Default,
-
587 SkipReuc = true,
-
588 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection("Merge Origin", 1.0)),
-
589 });
-
590
-
591 cancellationToken.ThrowIfCancellationRequested();
-
592
-
593 if (result.Status == MergeStatus.Conflicts)
-
594 {
-
595 logger.LogDebug("Merge conflict, aborting and reverting to {oldHeadFriendlyName}", oldHead.FriendlyName);
-
596 progressReporter.ReportProgress(0);
-
597 libGitRepo.Reset(ResetMode.Hard, oldTip, new CheckoutOptions
-
598 {
-
599 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($"Hard Reset to {oldHead.FriendlyName}", 1.0)),
-
600 });
-
601 cancellationToken.ThrowIfCancellationRequested();
-
602 }
+
576 var oldHead = libGitRepo.Head;
+
577 var oldTip = oldHead.Tip;
+
578
+
579 await Task.Factory.StartNew(
+
580 () =>
+
581 {
+
582 if (!Tracking)
+
583 throw new JobException(ErrorCode.RepoReferenceRequired);
+
584
+
585 libGitRepo.RemoveUntrackedFiles();
+
586
+
587 cancellationToken.ThrowIfCancellationRequested();
+
588
+
589 trackedBranch = libGitRepo.Head.TrackedBranch;
+
590 logger.LogDebug(
+
591 "Merge origin/{trackedBranch}: <{committerName} ({committerEmail})>",
+
592 trackedBranch.FriendlyName,
+
593 committerName,
+
594 committerEmail);
+
595 result = libGitRepo.Merge(trackedBranch, new Signature(committerName, committerEmail, DateTimeOffset.UtcNow), new MergeOptions
+
596 {
+
597 CommitOnSuccess = true,
+
598 FailOnConflict = true,
+
599 FastForwardStrategy = FastForwardStrategy.Default,
+
600 SkipReuc = true,
+
601 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection("Merge Origin", 1.0)),
+
602 });
603
-
604 libGitRepo.RemoveUntrackedFiles();
-
605 },
-
606 cancellationToken,
-
607 DefaultIOManager.BlockingTaskCreationOptions,
-
608 TaskScheduler.Current);
-
609
-
610 if (result!.Status == MergeStatus.Conflicts)
-
611 {
-
612 await eventConsumer.HandleEvent(
-
613 EventType.RepoMergeConflict,
-
614 new List<string>
-
615 {
-
616 oldTip.Sha,
-
617 trackedBranch!.Tip.Sha,
-
618 oldHead.FriendlyName ?? UnknownReference,
-
619 trackedBranch.FriendlyName,
-
620 },
-
621 deploymentPipeline,
-
622 cancellationToken);
-
623 return null;
-
624 }
-
625
-
626 return result.Status == MergeStatus.FastForward;
-
627 }
-
628
-
630 public async ValueTask<bool> Synchronize(
-
631 JobProgressReporter progressReporter,
-
632 string? username,
-
633 string? password,
-
634 string committerName,
-
635 string committerEmail,
-
636 bool synchronizeTrackedBranch,
-
637 bool deploymentPipeline,
-
638 CancellationToken cancellationToken)
-
639 {
-
640 ArgumentNullException.ThrowIfNull(committerName);
-
641 ArgumentNullException.ThrowIfNull(committerEmail);
-
642 ArgumentNullException.ThrowIfNull(progressReporter);
-
643
-
644 if (username == null && password == null)
-
645 {
-
646 logger.LogTrace("Not synchronizing due to lack of credentials!");
-
647 return false;
-
648 }
-
649
-
650 logger.LogTrace("Begin Synchronize...");
-
651
-
652 ArgumentNullException.ThrowIfNull(username);
-
653 ArgumentNullException.ThrowIfNull(password);
-
654
-
655 var startHead = Head;
+
604 cancellationToken.ThrowIfCancellationRequested();
+
605
+
606 if (result.Status == MergeStatus.Conflicts)
+
607 {
+
608 logger.LogDebug("Merge conflict, aborting and reverting to {oldHeadFriendlyName}", oldHead.FriendlyName);
+
609 progressReporter.ReportProgress(0);
+
610 libGitRepo.Reset(ResetMode.Hard, oldTip, new CheckoutOptions
+
611 {
+
612 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection($"Hard Reset to {oldHead.FriendlyName}", 1.0)),
+
613 });
+
614 cancellationToken.ThrowIfCancellationRequested();
+
615 }
+
616
+
617 libGitRepo.RemoveUntrackedFiles();
+
618 },
+
619 cancellationToken,
+
620 DefaultIOManager.BlockingTaskCreationOptions,
+
621 TaskScheduler.Current);
+
622
+
623 if (result!.Status == MergeStatus.Conflicts)
+
624 {
+
625 await eventConsumer.HandleEvent(
+
626 EventType.RepoMergeConflict,
+
627 new List<string>
+
628 {
+
629 oldTip.Sha,
+
630 trackedBranch!.Tip.Sha,
+
631 oldHead.FriendlyName ?? UnknownReference,
+
632 trackedBranch.FriendlyName,
+
633 },
+
634 deploymentPipeline,
+
635 cancellationToken);
+
636 return null;
+
637 }
+
638
+
639 return result.Status == MergeStatus.FastForward;
+
640 }
+
641
+
643 public async ValueTask<bool> Synchronize(
+
644 JobProgressReporter progressReporter,
+
645 string? username,
+
646 string? password,
+
647 string committerName,
+
648 string committerEmail,
+
649 bool synchronizeTrackedBranch,
+
650 bool deploymentPipeline,
+
651 CancellationToken cancellationToken)
+
652 {
+
653 ArgumentNullException.ThrowIfNull(committerName);
+
654 ArgumentNullException.ThrowIfNull(committerEmail);
+
655 ArgumentNullException.ThrowIfNull(progressReporter);
656
-
657 logger.LogTrace("Configuring <{committerName} ({committerEmail})> as author/committer", committerName, committerEmail);
-
658 await Task.Factory.StartNew(
-
659 () =>
-
660 {
-
661 libGitRepo.Config.Set("user.name", committerName);
-
662 cancellationToken.ThrowIfCancellationRequested();
-
663 libGitRepo.Config.Set("user.email", committerEmail);
-
664 },
-
665 cancellationToken,
-
666 DefaultIOManager.BlockingTaskCreationOptions,
-
667 TaskScheduler.Current);
-
668
-
669 cancellationToken.ThrowIfCancellationRequested();
-
670 try
-
671 {
-
672 await eventConsumer.HandleEvent(
-
673 EventType.RepoPreSynchronize,
-
674 new List<string>
-
675 {
-
676 ioManager.ResolvePath(),
-
677 },
-
678 deploymentPipeline,
-
679 cancellationToken);
-
680 }
-
681 finally
-
682 {
-
683 logger.LogTrace("Resetting and cleaning untracked files...");
-
684 await Task.Factory.StartNew(
-
685 () =>
-
686 {
-
687 libGitRepo.Reset(ResetMode.Hard, libGitRepo.Head.Tip, new CheckoutOptions
-
688 {
-
689 OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection("Hard reset and remove untracked files", 0.1)),
-
690 });
-
691 cancellationToken.ThrowIfCancellationRequested();
-
692 libGitRepo.RemoveUntrackedFiles();
-
693 },
-
694 cancellationToken,
-
695 DefaultIOManager.BlockingTaskCreationOptions,
-
696 TaskScheduler.Current);
-
697 }
-
698
-
699 var remainingProgressFactor = 0.9;
-
700 if (!synchronizeTrackedBranch)
-
701 {
-
702 await PushHeadToTemporaryBranch(
-
703 username,
-
704 password,
-
705 progressReporter.CreateSection("Push to temporary branch", remainingProgressFactor),
-
706 cancellationToken);
-
707 return false;
-
708 }
-
709
-
710 var sameHead = Head == startHead;
-
711 if (sameHead || !Tracking)
-
712 {
-
713 logger.LogTrace("Aborted synchronize due to {abortReason}!", sameHead ? "lack of changes" : "not being on tracked reference");
-
714 return false;
-
715 }
-
716
-
717 logger.LogInformation("Synchronizing with origin...");
-
718
-
719 return await Task.Factory.StartNew(
-
720 () =>
-
721 {
-
722 var remote = libGitRepo.Network.Remotes.First();
-
723 try
-
724 {
-
725 libGitRepo.Network.Push(
-
726 libGitRepo.Head,
-
727 GeneratePushOptions(
-
728 progressReporter.CreateSection("Push to origin", remainingProgressFactor),
-
729 username,
-
730 password,
-
731 cancellationToken));
-
732 return true;
-
733 }
-
734 catch (NonFastForwardException)
-
735 {
-
736 logger.LogInformation("Synchronize aborted, non-fast forward!");
-
737 return false;
-
738 }
-
739 catch (UserCancelledException e)
-
740 {
-
741 cancellationToken.ThrowIfCancellationRequested();
-
742 throw new InvalidOperationException("Caught UserCancelledException without cancellationToken triggering", e);
-
743 }
-
744 catch (LibGit2SharpException e)
-
745 {
-
746 logger.LogWarning(e, "Unable to make synchronization push!");
-
747 return false;
-
748 }
-
749 },
-
750 cancellationToken,
-
751 DefaultIOManager.BlockingTaskCreationOptions,
-
752 TaskScheduler.Current);
-
753 }
-
754
-
756 public Task<bool> IsSha(string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
-
757 () =>
-
758 {
-
759 // check if it's a tag
-
760 var gitObject = libGitRepo.Lookup(committish, ObjectType.Tag);
-
761 if (gitObject != null)
-
762 return false;
-
763 cancellationToken.ThrowIfCancellationRequested();
-
764
-
765 // check if it's a branch
-
766 if (libGitRepo.Branches[committish] != null)
-
767 return false;
-
768 cancellationToken.ThrowIfCancellationRequested();
-
769
-
770 // err on the side of references, if we can't look it up, assume its a reference
-
771 if (libGitRepo.Lookup<Commit>(committish) != null)
-
772 return true;
-
773 return false;
-
774 },
-
775 cancellationToken,
-
776 DefaultIOManager.BlockingTaskCreationOptions,
-
777 TaskScheduler.Current);
-
778
-
780 public Task<bool> CommittishIsParent(string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
-
781 () =>
-
782 {
-
783 var targetObject = libGitRepo.Lookup(committish);
-
784 if (targetObject == null)
-
785 {
-
786 logger.LogTrace("Committish {committish} not found in repository", committish);
-
787 return false;
-
788 }
-
789
-
790 if (targetObject is not Commit targetCommit)
-
791 {
-
792 if (targetObject is not TagAnnotation)
-
793 {
-
794 logger.LogTrace("Committish {committish} is a {type} and does not point to a commit!", committish, targetObject.GetType().Name);
-
795 return false;
-
796 }
-
797
-
798 targetCommit = targetObject.Peel<Commit>();
-
799 if (targetCommit == null)
-
800 {
-
801 logger.LogError(
-
802 "TagAnnotation {committish} was found but the commit associated with it could not be found in repository!",
-
803 committish);
-
804 return false;
-
805 }
-
806 }
-
807
-
808 cancellationToken.ThrowIfCancellationRequested();
-
809 var startSha = Head;
-
810 logger.LogTrace("Testing if {committish} is a parent of {startSha}...", committish, startSha);
-
811 MergeResult mergeResult;
-
812 try
-
813 {
-
814 mergeResult = libGitRepo.Merge(
-
815 targetCommit,
-
816 new Signature(
-
817 DefaultCommitterName,
-
818 DefaultCommitterEmail,
-
819 DateTimeOffset.UtcNow),
-
820 new MergeOptions
-
821 {
-
822 FastForwardStrategy = FastForwardStrategy.FastForwardOnly,
-
823 FailOnConflict = true,
-
824 });
-
825 }
-
826 catch (NonFastForwardException ex)
-
827 {
-
828 logger.LogTrace(ex, "{committish} is not a parent of {startSha}", committish, startSha);
-
829 return false;
-
830 }
-
831
-
832 if (mergeResult.Status == MergeStatus.UpToDate)
-
833 return true;
-
834
-
835 logger.LogTrace("{committish} is not a parent of {startSha} ({mergeStatus}). Moving back...", committish, startSha, mergeResult.Status);
-
836 commands.Checkout(
-
837 libGitRepo,
-
838 new CheckoutOptions
-
839 {
-
840 CheckoutModifiers = CheckoutModifiers.Force,
-
841 },
-
842 startSha);
-
843
-
844 return false;
-
845 },
-
846 cancellationToken,
-
847 DefaultIOManager.BlockingTaskCreationOptions,
-
848 TaskScheduler.Current);
-
849
-
851 public ValueTask<Models.TestMerge> GetTestMerge(
-
852 TestMergeParameters parameters,
-
853 RepositorySettings repositorySettings,
-
854 CancellationToken cancellationToken) => gitRemoteFeatures.GetTestMerge(
-
855 parameters,
-
856 repositorySettings,
-
857 cancellationToken);
-
858
-
860 public Task<DateTimeOffset> TimestampCommit(string sha, CancellationToken cancellationToken) => Task.Factory.StartNew(
-
861 () =>
-
862 {
-
863 ArgumentNullException.ThrowIfNull(sha);
-
864
-
865 var commit = libGitRepo.Lookup<Commit>(sha) ?? throw new JobException($"Commit {sha} does not exist in the repository!");
-
866 return commit.Committer.When.ToUniversalTime();
-
867 },
-
868 cancellationToken,
-
869 DefaultIOManager.BlockingTaskCreationOptions,
-
870 TaskScheduler.Current);
-
871
-
873 protected override void DisposeImpl()
-
874 {
-
875 logger.LogTrace("Disposing...");
-
876 libGitRepo.Dispose();
-
877 base.DisposeImpl();
-
878 }
-
879
-
887 void RawCheckout(string committish, bool moveCurrentReference, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
-
888 {
-
889 logger.LogTrace("Checkout: {committish}", committish);
+
657 if (username == null && password == null)
+
658 {
+
659 logger.LogTrace("Not synchronizing due to lack of credentials!");
+
660 return false;
+
661 }
+
662
+
663 logger.LogTrace("Begin Synchronize...");
+
664
+
665 ArgumentNullException.ThrowIfNull(username);
+
666 ArgumentNullException.ThrowIfNull(password);
+
667
+
668 var startHead = Head;
+
669
+
670 logger.LogTrace("Configuring <{committerName} ({committerEmail})> as author/committer", committerName, committerEmail);
+
671 await Task.Factory.StartNew(
+
672 () =>
+
673 {
+
674 libGitRepo.Config.Set("user.name", committerName);
+
675 cancellationToken.ThrowIfCancellationRequested();
+
676 libGitRepo.Config.Set("user.email", committerEmail);
+
677 },
+
678 cancellationToken,
+
679 DefaultIOManager.BlockingTaskCreationOptions,
+
680 TaskScheduler.Current);
+
681
+
682 cancellationToken.ThrowIfCancellationRequested();
+
683 try
+
684 {
+
685 await eventConsumer.HandleEvent(
+
686 EventType.RepoPreSynchronize,
+
687 new List<string>
+
688 {
+
689 ioManager.ResolvePath(),
+
690 },
+
691 deploymentPipeline,
+
692 cancellationToken);
+
693 }
+
694 finally
+
695 {
+
696 logger.LogTrace("Resetting and cleaning untracked files...");
+
697 await Task.Factory.StartNew(
+
698 () =>
+
699 {
+
700 using var resetProgress = progressReporter.CreateSection("Hard reset and remove untracked files", 0.1);
+
701 libGitRepo.Reset(ResetMode.Hard, libGitRepo.Head.Tip, new CheckoutOptions
+
702 {
+
703 OnCheckoutProgress = CheckoutProgressHandler(resetProgress),
+
704 });
+
705 cancellationToken.ThrowIfCancellationRequested();
+
706 libGitRepo.RemoveUntrackedFiles();
+
707 },
+
708 cancellationToken,
+
709 DefaultIOManager.BlockingTaskCreationOptions,
+
710 TaskScheduler.Current);
+
711 }
+
712
+
713 var remainingProgressFactor = 0.9;
+
714 if (!synchronizeTrackedBranch)
+
715 {
+
716 using var progressReporter2 = progressReporter.CreateSection("Push to temporary branch", remainingProgressFactor);
+
717 await PushHeadToTemporaryBranch(
+
718 username,
+
719 password,
+
720 progressReporter2,
+
721 cancellationToken);
+
722 return false;
+
723 }
+
724
+
725 var sameHead = Head == startHead;
+
726 if (sameHead || !Tracking)
+
727 {
+
728 logger.LogTrace("Aborted synchronize due to {abortReason}!", sameHead ? "lack of changes" : "not being on tracked reference");
+
729 return false;
+
730 }
+
731
+
732 logger.LogInformation("Synchronizing with origin...");
+
733
+
734 return await Task.Factory.StartNew(
+
735 () =>
+
736 {
+
737 var remote = libGitRepo.Network.Remotes.First();
+
738 try
+
739 {
+
740 using var pushReporter = progressReporter.CreateSection("Push to origin", remainingProgressFactor);
+
741 var (pushOptions, progressReporters) = GeneratePushOptions(
+
742 pushReporter,
+
743 username,
+
744 password,
+
745 cancellationToken);
+
746 try
+
747 {
+
748 libGitRepo.Network.Push(
+
749 libGitRepo.Head,
+
750 pushOptions);
+
751 }
+
752 finally
+
753 {
+
754 foreach (var progressReporter in progressReporters)
+
755 progressReporter.Dispose();
+
756 }
+
757
+
758 return true;
+
759 }
+
760 catch (NonFastForwardException)
+
761 {
+
762 logger.LogInformation("Synchronize aborted, non-fast forward!");
+
763 return false;
+
764 }
+
765 catch (UserCancelledException e)
+
766 {
+
767 cancellationToken.ThrowIfCancellationRequested();
+
768 throw new InvalidOperationException("Caught UserCancelledException without cancellationToken triggering", e);
+
769 }
+
770 catch (LibGit2SharpException e)
+
771 {
+
772 logger.LogWarning(e, "Unable to make synchronization push!");
+
773 return false;
+
774 }
+
775 },
+
776 cancellationToken,
+
777 DefaultIOManager.BlockingTaskCreationOptions,
+
778 TaskScheduler.Current);
+
779 }
+
780
+
782 public Task<bool> IsSha(string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
+
783 () =>
+
784 {
+
785 // check if it's a tag
+
786 var gitObject = libGitRepo.Lookup(committish, ObjectType.Tag);
+
787 if (gitObject != null)
+
788 return false;
+
789 cancellationToken.ThrowIfCancellationRequested();
+
790
+
791 // check if it's a branch
+
792 if (libGitRepo.Branches[committish] != null)
+
793 return false;
+
794 cancellationToken.ThrowIfCancellationRequested();
+
795
+
796 // err on the side of references, if we can't look it up, assume its a reference
+
797 if (libGitRepo.Lookup<Commit>(committish) != null)
+
798 return true;
+
799 return false;
+
800 },
+
801 cancellationToken,
+
802 DefaultIOManager.BlockingTaskCreationOptions,
+
803 TaskScheduler.Current);
+
804
+
806 public Task<bool> CommittishIsParent(string committish, CancellationToken cancellationToken) => Task.Factory.StartNew(
+
807 () =>
+
808 {
+
809 var targetObject = libGitRepo.Lookup(committish);
+
810 if (targetObject == null)
+
811 {
+
812 logger.LogTrace("Committish {committish} not found in repository", committish);
+
813 return false;
+
814 }
+
815
+
816 if (targetObject is not Commit targetCommit)
+
817 {
+
818 if (targetObject is not TagAnnotation)
+
819 {
+
820 logger.LogTrace("Committish {committish} is a {type} and does not point to a commit!", committish, targetObject.GetType().Name);
+
821 return false;
+
822 }
+
823
+
824 targetCommit = targetObject.Peel<Commit>();
+
825 if (targetCommit == null)
+
826 {
+
827 logger.LogError(
+
828 "TagAnnotation {committish} was found but the commit associated with it could not be found in repository!",
+
829 committish);
+
830 return false;
+
831 }
+
832 }
+
833
+
834 cancellationToken.ThrowIfCancellationRequested();
+
835 var startSha = Head;
+
836 logger.LogTrace("Testing if {committish} is a parent of {startSha}...", committish, startSha);
+
837 MergeResult mergeResult;
+
838 try
+
839 {
+
840 mergeResult = libGitRepo.Merge(
+
841 targetCommit,
+
842 new Signature(
+
843 DefaultCommitterName,
+
844 DefaultCommitterEmail,
+
845 DateTimeOffset.UtcNow),
+
846 new MergeOptions
+
847 {
+
848 FastForwardStrategy = FastForwardStrategy.FastForwardOnly,
+
849 FailOnConflict = true,
+
850 });
+
851 }
+
852 catch (NonFastForwardException ex)
+
853 {
+
854 logger.LogTrace(ex, "{committish} is not a parent of {startSha}", committish, startSha);
+
855 return false;
+
856 }
+
857
+
858 if (mergeResult.Status == MergeStatus.UpToDate)
+
859 return true;
+
860
+
861 logger.LogTrace("{committish} is not a parent of {startSha} ({mergeStatus}). Moving back...", committish, startSha, mergeResult.Status);
+
862 commands.Checkout(
+
863 libGitRepo,
+
864 new CheckoutOptions
+
865 {
+
866 CheckoutModifiers = CheckoutModifiers.Force,
+
867 },
+
868 startSha);
+
869
+
870 return false;
+
871 },
+
872 cancellationToken,
+
873 DefaultIOManager.BlockingTaskCreationOptions,
+
874 TaskScheduler.Current);
+
875
+
877 public ValueTask<Models.TestMerge> GetTestMerge(
+
878 TestMergeParameters parameters,
+
879 RepositorySettings repositorySettings,
+
880 CancellationToken cancellationToken) => gitRemoteFeatures.GetTestMerge(
+
881 parameters,
+
882 repositorySettings,
+
883 cancellationToken);
+
884
+
886 public Task<DateTimeOffset> TimestampCommit(string sha, CancellationToken cancellationToken) => Task.Factory.StartNew(
+
887 () =>
+
888 {
+
889 ArgumentNullException.ThrowIfNull(sha);
890
-
891 var checkoutOptions = new CheckoutOptions
-
892 {
-
893 CheckoutModifiers = CheckoutModifiers.Force,
-
894 };
-
895
-
896 if (progressReporter != null)
-
897 {
-
898 var stage = $"Checkout {committish}";
-
899 progressReporter = progressReporter.CreateSection(stage, 1.0);
-
900 progressReporter.ReportProgress(0);
-
901 checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(progressReporter);
-
902 }
-
903
-
904 cancellationToken.ThrowIfCancellationRequested();
+
891 var commit = libGitRepo.Lookup<Commit>(sha) ?? throw new JobException($"Commit {sha} does not exist in the repository!");
+
892 return commit.Committer.When.ToUniversalTime();
+
893 },
+
894 cancellationToken,
+
895 DefaultIOManager.BlockingTaskCreationOptions,
+
896 TaskScheduler.Current);
+
897
+
899 protected override void DisposeImpl()
+
900 {
+
901 logger.LogTrace("Disposing...");
+
902 libGitRepo.Dispose();
+
903 base.DisposeImpl();
+
904 }
905
-
906 if (moveCurrentReference)
-
907 {
-
908 if (Reference == NoReference)
-
909 throw new InvalidOperationException("Cannot move current reference when not on reference!");
-
910
-
911 var gitObject = libGitRepo.Lookup(committish);
-
912 if (gitObject == null)
-
913 throw new JobException($"Could not find committish: {committish}");
-
914
-
915 var commit = gitObject.Peel<Commit>();
+
913 void RawCheckout(string committish, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
+
914 {
+
915 logger.LogTrace("Checkout: {committish}", committish);
916
-
917 cancellationToken.ThrowIfCancellationRequested();
-
918
-
919 libGitRepo.Reset(ResetMode.Hard, commit, checkoutOptions);
-
920 }
-
921 else
-
922 {
-
923 void RunCheckout() => commands.Checkout(
-
924 libGitRepo,
-
925 checkoutOptions,
-
926 committish);
-
927
-
928 try
-
929 {
-
930 RunCheckout();
-
931 }
-
932 catch (NotFoundException)
-
933 {
-
934 // Maybe (likely) a remote?
-
935 var remoteName = $"origin/{committish}";
-
936 var remoteBranch = libGitRepo.Branches.FirstOrDefault(
-
937 branch => branch.FriendlyName.Equals(remoteName, StringComparison.Ordinal));
-
938 cancellationToken.ThrowIfCancellationRequested();
+
917 var checkoutOptions = new CheckoutOptions
+
918 {
+
919 CheckoutModifiers = CheckoutModifiers.Force,
+
920 };
+
921
+
922 var stage = $"Checkout {committish}";
+
923 using var newProgressReporter = progressReporter.CreateSection(stage, 1.0);
+
924 newProgressReporter.ReportProgress(0);
+
925 checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(newProgressReporter);
+
926
+
927 cancellationToken.ThrowIfCancellationRequested();
+
928
+
929 if (moveCurrentReference)
+
930 {
+
931 if (Reference == NoReference)
+
932 throw new InvalidOperationException("Cannot move current reference when not on reference!");
+
933
+
934 var gitObject = libGitRepo.Lookup(committish);
+
935 if (gitObject == null)
+
936 throw new JobException($"Could not find committish: {committish}");
+
937
+
938 var commit = gitObject.Peel<Commit>();
939
-
940 if (remoteBranch == default)
-
941 throw;
-
942
-
943 logger.LogDebug("Creating local branch for {remoteBranchFriendlyName}...", remoteBranch.FriendlyName);
-
944 var branch = libGitRepo.CreateBranch(committish, remoteBranch.Tip);
-
945
-
946 libGitRepo.Branches.Update(branch, branchUpdate => branchUpdate.TrackedBranch = remoteBranch.CanonicalName);
-
947
-
948 cancellationToken.ThrowIfCancellationRequested();
-
949
-
950 RunCheckout();
-
951 }
-
952 }
-
953
-
954 cancellationToken.ThrowIfCancellationRequested();
-
955
-
956 libGitRepo.RemoveUntrackedFiles();
-
957 }
-
958
-
967 Task PushHeadToTemporaryBranch(string username, string password, JobProgressReporter progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
-
968 () =>
-
969 {
-
970 logger.LogInformation("Pushing changes to temporary remote branch...");
-
971 var branch = libGitRepo.CreateBranch(RemoteTemporaryBranchName);
-
972 try
-
973 {
-
974 cancellationToken.ThrowIfCancellationRequested();
-
975 var remote = libGitRepo.Network.Remotes.First();
-
976 try
-
977 {
-
978 var forcePushString = String.Format(CultureInfo.InvariantCulture, "+{0}:{0}", branch.CanonicalName);
-
979 libGitRepo.Network.Push(remote, forcePushString, GeneratePushOptions(progressReporter.CreateSection(null, 0.9), username, password, cancellationToken));
-
980 var removalString = String.Format(CultureInfo.InvariantCulture, ":{0}", branch.CanonicalName);
-
981 libGitRepo.Network.Push(remote, removalString, GeneratePushOptions(progressReporter.CreateSection(null, 0.1), username, password, cancellationToken));
-
982 }
-
983 catch (UserCancelledException)
-
984 {
-
985 cancellationToken.ThrowIfCancellationRequested();
-
986 }
-
987 catch (LibGit2SharpException e)
-
988 {
-
989 logger.LogWarning(e, "Unable to push to temporary branch!");
-
990 }
-
991 }
-
992 finally
-
993 {
-
994 libGitRepo.Branches.Remove(branch);
-
995 }
-
996 },
-
997 cancellationToken,
-
998 DefaultIOManager.BlockingTaskCreationOptions,
-
999 TaskScheduler.Current);
-
1000
-
1009 PushOptions GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
-
1010 {
-
1011 var subProgressReporter = progressReporter.CreateSection(null, 0.5);
-
1012
-
1013 return new PushOptions
-
1014 {
-
1015 OnPackBuilderProgress = (stage, current, total) =>
-
1016 {
-
1017 var baseProgress = stage == PackBuilderStage.Counting ? 0 : 0.5;
-
1018 var addon = total > 0 && current <= total ? (0.5 * ((double)current / total)) : 0;
-
1019 progressReporter.ReportProgress(baseProgress + addon);
-
1020 return !cancellationToken.IsCancellationRequested;
-
1021 },
-
1022 OnNegotiationCompletedBeforePush = (a) =>
-
1023 {
-
1024 subProgressReporter = progressReporter.CreateSection(null, 0.5);
-
1025 return !cancellationToken.IsCancellationRequested;
-
1026 },
-
1027 OnPushTransferProgress = (a, sentBytes, totalBytes) =>
-
1028 {
-
1029 progressReporter.ReportProgress((double)sentBytes / totalBytes);
-
1030 return !cancellationToken.IsCancellationRequested;
-
1031 },
-
1032 CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
-
1033 };
-
1034 }
-
1035
-
1040 string GetRepositoryPath()
-
1041 => ioManager.GetDirectoryName(libGitRepo
-
1042 .Info
-
1043 .Path
-
1044 .TrimEnd(Path.DirectorySeparatorChar)
-
1045 .TrimEnd(Path.AltDirectorySeparatorChar));
-
1046
-
1056 ValueTask UpdateSubmodules(
-
1057 JobProgressReporter? progressReporter,
-
1058 string? username,
-
1059 string? password,
-
1060 bool deploymentPipeline,
-
1061 CancellationToken cancellationToken)
+
940 cancellationToken.ThrowIfCancellationRequested();
+
941
+
942 libGitRepo.Reset(ResetMode.Hard, commit, checkoutOptions);
+
943 }
+
944 else
+
945 {
+
946 void RunCheckout() => commands.Checkout(
+
947 libGitRepo,
+
948 checkoutOptions,
+
949 committish);
+
950
+
951 try
+
952 {
+
953 RunCheckout();
+
954 }
+
955 catch (NotFoundException)
+
956 {
+
957 // Maybe (likely) a remote?
+
958 var remoteName = $"origin/{committish}";
+
959 var remoteBranch = libGitRepo.Branches.FirstOrDefault(
+
960 branch => branch.FriendlyName.Equals(remoteName, StringComparison.Ordinal));
+
961 cancellationToken.ThrowIfCancellationRequested();
+
962
+
963 if (remoteBranch == default)
+
964 throw;
+
965
+
966 logger.LogDebug("Creating local branch for {remoteBranchFriendlyName}...", remoteBranch.FriendlyName);
+
967 var branch = libGitRepo.CreateBranch(committish, remoteBranch.Tip);
+
968
+
969 libGitRepo.Branches.Update(branch, branchUpdate => branchUpdate.TrackedBranch = remoteBranch.CanonicalName);
+
970
+
971 cancellationToken.ThrowIfCancellationRequested();
+
972
+
973 RunCheckout();
+
974 }
+
975 }
+
976
+
977 cancellationToken.ThrowIfCancellationRequested();
+
978
+
979 libGitRepo.RemoveUntrackedFiles();
+
980 }
+
981
+
990 Task PushHeadToTemporaryBranch(string username, string password, JobProgressReporter progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
+
991 () =>
+
992 {
+
993 logger.LogInformation("Pushing changes to temporary remote branch...");
+
994 var branch = libGitRepo.CreateBranch(RemoteTemporaryBranchName);
+
995 try
+
996 {
+
997 cancellationToken.ThrowIfCancellationRequested();
+
998 var remote = libGitRepo.Network.Remotes.First();
+
999 try
+
1000 {
+
1001 var forcePushString = String.Format(CultureInfo.InvariantCulture, "+{0}:{0}", branch.CanonicalName);
+
1002
+
1003 using (var mainPushReporter = progressReporter.CreateSection(null, 0.9))
+
1004 {
+
1005 var (pushOptions, progressReporters) = GeneratePushOptions(
+
1006 mainPushReporter,
+
1007 username,
+
1008 password,
+
1009 cancellationToken);
+
1010
+
1011 try
+
1012 {
+
1013 libGitRepo.Network.Push(remote, forcePushString, pushOptions);
+
1014 }
+
1015 finally
+
1016 {
+
1017 foreach (var progressReporter in progressReporters)
+
1018 progressReporter.Dispose();
+
1019 }
+
1020 }
+
1021
+
1022 var removalString = String.Format(CultureInfo.InvariantCulture, ":{0}", branch.CanonicalName);
+
1023 using var forcePushReporter = progressReporter.CreateSection(null, 0.1);
+
1024 var (forcePushOptions, forcePushReporters) = GeneratePushOptions(forcePushReporter, username, password, cancellationToken);
+
1025 try
+
1026 {
+
1027 libGitRepo.Network.Push(remote, removalString, forcePushOptions);
+
1028 }
+
1029 finally
+
1030 {
+
1031 foreach (var subForcePushReporter in forcePushReporters)
+
1032 forcePushReporter.Dispose();
+
1033 }
+
1034 }
+
1035 catch (UserCancelledException)
+
1036 {
+
1037 cancellationToken.ThrowIfCancellationRequested();
+
1038 }
+
1039 catch (LibGit2SharpException e)
+
1040 {
+
1041 logger.LogWarning(e, "Unable to push to temporary branch!");
+
1042 }
+
1043 }
+
1044 finally
+
1045 {
+
1046 libGitRepo.Branches.Remove(branch);
+
1047 }
+
1048 },
+
1049 cancellationToken,
+
1050 DefaultIOManager.BlockingTaskCreationOptions,
+
1051 TaskScheduler.Current);
+
1052
+
1061 (PushOptions PushOptions, IEnumerable<JobProgressReporter> SubProgressReporters) GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
1062 {
-
1063 logger.LogTrace("Updating submodules {withOrWithout} credentials...", username == null ? "without" : "with");
-
1064
-
1065 async ValueTask RecursiveUpdateSubmodules(LibGit2Sharp.IRepository parentRepository, JobProgressReporter? currentProgressReporter, string parentGitDirectory)
-
1066 {
-
1067 var submoduleCount = libGitRepo.Submodules.Count();
-
1068 if (submoduleCount == 0)
+
1063 var packFileCountingReporter = progressReporter.CreateSection(null, 0.25);
+
1064 var packFileDeltafyingReporter = progressReporter.CreateSection(null, 0.25);
+
1065 var transferProgressReporter = progressReporter.CreateSection(null, 0.5);
+
1066
+
1067 return (
+
1068 PushOptions: new PushOptions
1069 {
-
1070 logger.LogTrace("No submodules, skipping update");
-
1071 return;
-
1072 }
-
1073
-
1074 var factor = 1.0 / submoduleCount / 3;
-
1075 foreach (var submodule in parentRepository.Submodules)
-
1076 {
-
1077 logger.LogTrace("Entering submodule {name} ({path}) for recursive updates...", submodule.Name, submodule.Path);
-
1078 var submoduleUpdateOptions = new SubmoduleUpdateOptions
-
1079 {
-
1080 Init = true,
-
1081 OnCheckoutNotify = (_, _) => !cancellationToken.IsCancellationRequested,
-
1082 };
-
1083
-
1084 submoduleUpdateOptions.FetchOptions.Hydrate(
-
1085 logger,
-
1086 currentProgressReporter?.CreateSection($"Fetch submodule {submodule.Name}", factor),
-
1087 credentialsProvider.GenerateCredentialsHandler(username, password),
-
1088 cancellationToken);
-
1089
-
1090 if (currentProgressReporter != null)
-
1091 submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler(
-
1092 currentProgressReporter.CreateSection($"Checkout submodule {submodule.Name}", factor));
-
1093
-
1094 logger.LogDebug("Updating submodule {submoduleName}...", submodule.Name);
-
1095 Task RawSubModuleUpdate() => Task.Factory.StartNew(
-
1096 () => parentRepository.Submodules.Update(submodule.Name, submoduleUpdateOptions),
-
1097 cancellationToken,
-
1098 DefaultIOManager.BlockingTaskCreationOptions,
-
1099 TaskScheduler.Current);
-
1100
-
1101 try
-
1102 {
-
1103 await RawSubModuleUpdate();
-
1104 }
-
1105 catch (LibGit2SharpException ex) when (parentRepository == libGitRepo)
-
1106 {
-
1107 // workaround for https://github.com/libgit2/libgit2/issues/3820
-
1108 // kill off the modules/ folder in .git and try again
-
1109 currentProgressReporter?.ReportProgress(null);
-
1110 credentialsProvider.CheckBadCredentialsException(ex);
-
1111 logger.LogWarning(ex, "Initial update of submodule {submoduleName} failed. Deleting submodule directories and re-attempting...", submodule.Name);
-
1112
-
1113 await Task.WhenAll(
-
1114 ioManager.DeleteDirectory($".git/modules/{submodule.Path}", cancellationToken),
-
1115 ioManager.DeleteDirectory(submodule.Path, cancellationToken));
-
1116
-
1117 logger.LogTrace("Second update attempt for submodule {submoduleName}...", submodule.Name);
-
1118 try
-
1119 {
-
1120 await RawSubModuleUpdate();
-
1121 }
-
1122 catch (UserCancelledException)
-
1123 {
-
1124 cancellationToken.ThrowIfCancellationRequested();
-
1125 }
-
1126 catch (LibGit2SharpException ex2)
-
1127 {
-
1128 credentialsProvider.CheckBadCredentialsException(ex2);
-
1129 logger.LogTrace(ex2, "Retried update of submodule {submoduleName} failed!", submodule.Name);
-
1130 throw new AggregateException(ex, ex2);
-
1131 }
-
1132 }
-
1133
-
1134 await eventConsumer.HandleEvent(
-
1135 EventType.RepoSubmoduleUpdate,
-
1136 new List<string> { submodule.Name },
-
1137 deploymentPipeline,
-
1138 cancellationToken);
-
1139
-
1140 var submodulePath = ioManager.ResolvePath(
-
1141 ioManager.ConcatPath(
-
1142 parentGitDirectory,
-
1143 submodule.Path));
+
1070 OnPackBuilderProgress = (stage, current, total) =>
+
1071 {
+
1072 if (total < current)
+
1073 total = current;
+
1074
+
1075 var percentage = ((double)current) / total;
+
1076 (stage == PackBuilderStage.Counting ? packFileCountingReporter : packFileDeltafyingReporter).ReportProgress(percentage);
+
1077 return !cancellationToken.IsCancellationRequested;
+
1078 },
+
1079 OnNegotiationCompletedBeforePush = (a) => !cancellationToken.IsCancellationRequested,
+
1080 OnPushTransferProgress = (a, sentBytes, totalBytes) =>
+
1081 {
+
1082 packFileCountingReporter.ReportProgress((double)sentBytes / totalBytes);
+
1083 return !cancellationToken.IsCancellationRequested;
+
1084 },
+
1085 CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
+
1086 },
+
1087 SubProgressReporters: new List<JobProgressReporter>
+
1088 {
+
1089 packFileCountingReporter,
+
1090 packFileDeltafyingReporter,
+
1091 transferProgressReporter,
+
1092 });
+
1093 }
+
1094
+
1099 string GetRepositoryPath()
+
1100 => ioManager.GetDirectoryName(libGitRepo
+
1101 .Info
+
1102 .Path
+
1103 .TrimEnd(Path.DirectorySeparatorChar)
+
1104 .TrimEnd(Path.AltDirectorySeparatorChar));
+
1105
+
1115 ValueTask UpdateSubmodules(
+
1116 JobProgressReporter progressReporter,
+
1117 string? username,
+
1118 string? password,
+
1119 bool deploymentPipeline,
+
1120 CancellationToken cancellationToken)
+
1121 {
+
1122 logger.LogTrace("Updating submodules {withOrWithout} credentials...", username == null ? "without" : "with");
+
1123
+
1124 async ValueTask RecursiveUpdateSubmodules(LibGit2Sharp.IRepository parentRepository, JobProgressReporter currentProgressReporter, string parentGitDirectory)
+
1125 {
+
1126 var submoduleCount = libGitRepo.Submodules.Count();
+
1127 if (submoduleCount == 0)
+
1128 {
+
1129 logger.LogTrace("No submodules, skipping update");
+
1130 return;
+
1131 }
+
1132
+
1133 var factor = 1.0 / submoduleCount / 3;
+
1134 foreach (var submodule in parentRepository.Submodules)
+
1135 {
+
1136 logger.LogTrace("Entering submodule {name} ({path}) for recursive updates...", submodule.Name, submodule.Path);
+
1137 var submoduleUpdateOptions = new SubmoduleUpdateOptions
+
1138 {
+
1139 Init = true,
+
1140 OnCheckoutNotify = (_, _) => !cancellationToken.IsCancellationRequested,
+
1141 };
+
1142
+
1143 using var fetchReporter = currentProgressReporter.CreateSection($"Fetch submodule {submodule.Name}", factor);
1144
-
1145 using var submoduleRepo = await submoduleFactory.CreateFromPath(
-
1146 submodulePath,
-
1147 cancellationToken);
-
1148 await RecursiveUpdateSubmodules(
-
1149 submoduleRepo,
-
1150 currentProgressReporter?.CreateSection($"Entering submodule \"{submodule.Name}\"...", factor),
-
1151 submodulePath);
-
1152 }
-
1153 }
-
1154
-
1155 return RecursiveUpdateSubmodules(libGitRepo, progressReporter, GetRepositoryPath());
-
1156 }
-
1157
-
1163 CheckoutProgressHandler CheckoutProgressHandler(JobProgressReporter progressReporter) => (a, completedSteps, totalSteps) =>
-
1164 {
-
1165 double? percentage;
-
1166
-
1167 // short circuit initialization where totalSteps is 0
-
1168 if (completedSteps == 0)
-
1169 percentage = 0;
-
1170 else if (totalSteps < completedSteps || totalSteps == 0)
-
1171 percentage = null;
-
1172 else
-
1173 {
-
1174 percentage = ((double)completedSteps) / totalSteps;
-
1175 if (percentage < 0)
-
1176 percentage = null;
-
1177 }
-
1178
-
1179 if (percentage == null)
-
1180 logger.LogDebug(
-
1181 "Bad checkout progress values (Please tell Dominion)! Completeds: {completed}, Total: {total}",
-
1182 completedSteps,
-
1183 totalSteps);
-
1184
-
1185 progressReporter.ReportProgress(percentage);
-
1186 };
-
1187 }
-
1188#pragma warning restore CA1506
-
1189}
+
1145 submoduleUpdateOptions.FetchOptions.Hydrate(
+
1146 logger,
+
1147 fetchReporter,
+
1148 credentialsProvider.GenerateCredentialsHandler(username, password),
+
1149 cancellationToken);
+
1150
+
1151 using var checkoutReporter = currentProgressReporter.CreateSection($"Checkout submodule {submodule.Name}", factor);
+
1152 submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler(checkoutReporter);
+
1153
+
1154 logger.LogDebug("Updating submodule {submoduleName}...", submodule.Name);
+
1155 Task RawSubModuleUpdate() => Task.Factory.StartNew(
+
1156 () => parentRepository.Submodules.Update(submodule.Name, submoduleUpdateOptions),
+
1157 cancellationToken,
+
1158 DefaultIOManager.BlockingTaskCreationOptions,
+
1159 TaskScheduler.Current);
+
1160
+
1161 try
+
1162 {
+
1163 await RawSubModuleUpdate();
+
1164 }
+
1165 catch (LibGit2SharpException ex) when (parentRepository == libGitRepo)
+
1166 {
+
1167 // workaround for https://github.com/libgit2/libgit2/issues/3820
+
1168 // kill off the modules/ folder in .git and try again
+
1169 currentProgressReporter.ReportProgress(0);
+
1170 credentialsProvider.CheckBadCredentialsException(ex);
+
1171 logger.LogWarning(ex, "Initial update of submodule {submoduleName} failed. Deleting submodule directories and re-attempting...", submodule.Name);
+
1172
+
1173 await Task.WhenAll(
+
1174 ioManager.DeleteDirectory($".git/modules/{submodule.Path}", cancellationToken),
+
1175 ioManager.DeleteDirectory(submodule.Path, cancellationToken));
+
1176
+
1177 logger.LogTrace("Second update attempt for submodule {submoduleName}...", submodule.Name);
+
1178 try
+
1179 {
+
1180 await RawSubModuleUpdate();
+
1181 }
+
1182 catch (UserCancelledException)
+
1183 {
+
1184 cancellationToken.ThrowIfCancellationRequested();
+
1185 }
+
1186 catch (LibGit2SharpException ex2)
+
1187 {
+
1188 credentialsProvider.CheckBadCredentialsException(ex2);
+
1189 logger.LogTrace(ex2, "Retried update of submodule {submoduleName} failed!", submodule.Name);
+
1190 throw new AggregateException(ex, ex2);
+
1191 }
+
1192 }
+
1193
+
1194 await eventConsumer.HandleEvent(
+
1195 EventType.RepoSubmoduleUpdate,
+
1196 new List<string> { submodule.Name },
+
1197 deploymentPipeline,
+
1198 cancellationToken);
+
1199
+
1200 var submodulePath = ioManager.ResolvePath(
+
1201 ioManager.ConcatPath(
+
1202 parentGitDirectory,
+
1203 submodule.Path));
+
1204
+
1205 using var submoduleRepo = await submoduleFactory.CreateFromPath(
+
1206 submodulePath,
+
1207 cancellationToken);
+
1208
+
1209 using var submoduleReporter = currentProgressReporter.CreateSection($"Entering submodule \"{submodule.Name}\"...", factor);
+
1210 await RecursiveUpdateSubmodules(
+
1211 submoduleRepo,
+
1212 submoduleReporter,
+
1213 submodulePath);
+
1214 }
+
1215 }
+
1216
+
1217 return RecursiveUpdateSubmodules(libGitRepo, progressReporter, GetRepositoryPath());
+
1218 }
+
1219
+
1225 CheckoutProgressHandler CheckoutProgressHandler(JobProgressReporter progressReporter) => (a, completedSteps, totalSteps) =>
+
1226 {
+
1227 double? percentage;
+
1228
+
1229 // short circuit initialization where totalSteps is 0
+
1230 if (completedSteps == 0)
+
1231 percentage = 0;
+
1232 else if (totalSteps < completedSteps || totalSteps == 0)
+
1233 percentage = null;
+
1234 else
+
1235 {
+
1236 percentage = ((double)completedSteps) / totalSteps;
+
1237 if (percentage < 0)
+
1238 percentage = null;
+
1239 }
+
1240
+
1241 if (percentage == null)
+
1242 logger.LogDebug(
+
1243 "Bad checkout progress values (Please tell Dominion)! Completeds: {completed}, Total: {total}",
+
1244 completedSteps,
+
1245 totalSteps);
+
1246
+
1247 progressReporter.ReportProgress(percentage);
+
1248 };
+
1249 }
+
1250#pragma warning restore CA1506
+
1251}
Tgstation.Server.Api.Models.Internal.RepositorySettings
Represents configurable settings for a git repository.
Definition: RepositorySettings.cs:9
Tgstation.Server.Api.Models.TestMergeParameters
Parameters for creating a TestMerge.
Definition: TestMergeParameters.cs:9
Tgstation.Server.Api.Models.TestMergeParameters.TargetCommitSha
virtual ? string TargetCommitSha
The sha of the test merge revision to merge. If not specified, the latest commit from the source will...
Definition: TestMergeParameters.cs:20
@@ -1152,32 +1214,30 @@ $(function() {
Tgstation.Server.Host.Components.Repository.Repository.OriginTrackingErrorTemplate
const string OriginTrackingErrorTemplate
Template error message for when tracking of the most recent origin commit fails.
Definition: Repository.cs:42
Tgstation.Server.Host.Components.Repository.Repository.ResetToSha
Task ResetToSha(string sha, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Requires the current HEAD to be a reference. Hard resets the reference to the given sha....
Tgstation.Server.Host.Components.Repository.Repository.DefaultCommitterEmail
const string DefaultCommitterEmail
The default password for committers.
Definition: Repository.cs:37
-
Tgstation.Server.Host.Components.Repository.Repository.CopyTo
async ValueTask CopyTo(string path, CancellationToken cancellationToken)
Copies the current working directory to a given path . A ValueTask representing the running operation...
Definition: Repository.cs:516
-
Tgstation.Server.Host.Components.Repository.Repository.UpdateSubmodules
ValueTask UpdateSubmodules(JobProgressReporter? progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Recusively update all Submodules in the libGitRepo.
Definition: Repository.cs:1056
+
Tgstation.Server.Host.Components.Repository.Repository.FetchOrigin
async ValueTask FetchOrigin(JobProgressReporter progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Fetch commits from the origin repository. A ValueTask representing the running operation.
Definition: Repository.cs:418
+
Tgstation.Server.Host.Components.Repository.Repository.CopyTo
async ValueTask CopyTo(string path, CancellationToken cancellationToken)
Copies the current working directory to a given path . A ValueTask representing the running operation...
Definition: Repository.cs:529
Tgstation.Server.Host.Components.Repository.Repository.AddTestMerge
async ValueTask< TestMergeResult > AddTestMerge(TestMergeParameters testMergeParameters, string committerName, string committerEmail, string? username, string? password, bool updateSubmodules, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Attempt to merge the revision specified by a given set of testMergeParameters into HEAD....
Definition: Repository.cs:175
Tgstation.Server.Host.Components.Repository.Repository.Head
string Head
The SHA of the IRepository HEAD.
Definition: Repository.cs:72
Tgstation.Server.Host.Components.Repository.Repository.RemoteRepositoryName
string? RemoteRepositoryName
If RemoteGitProvider is not RemoteGitProvider.Unknown this will be set with the name of the repositor...
Definition: Repository.cs:66
Tgstation.Server.Host.Components.Repository.Repository.Tracking
bool Tracking
If Reference tracks an upstream branch.
Definition: Repository.cs:69
Tgstation.Server.Host.Components.Repository.Repository.RemoteTemporaryBranchName
const string RemoteTemporaryBranchName
The branch name used for publishing testmerge commits.
Definition: Repository.cs:47
-
Tgstation.Server.Host.Components.Repository.Repository.Synchronize
async ValueTask< bool > Synchronize(JobProgressReporter progressReporter, string? username, string? password, string committerName, string committerEmail, bool synchronizeTrackedBranch, bool deploymentPipeline, CancellationToken cancellationToken)
Runs the synchronize event script and attempts to push any changes made to the IRepository if on a tr...
Definition: Repository.cs:630
+
Tgstation.Server.Host.Components.Repository.Repository.Synchronize
async ValueTask< bool > Synchronize(JobProgressReporter progressReporter, string? username, string? password, string committerName, string committerEmail, bool synchronizeTrackedBranch, bool deploymentPipeline, CancellationToken cancellationToken)
Runs the synchronize event script and attempts to push any changes made to the IRepository if on a tr...
Definition: Repository.cs:643
Tgstation.Server.Host.Components.Repository.Repository.Origin
Uri Origin
The current origin remote the IRepository is using.
Definition: Repository.cs:78
+
Tgstation.Server.Host.Components.Repository.Repository.CheckoutObject
async ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Checks out a given committish . A ValueTask representing the running operation.
Definition: Repository.cs:377
Tgstation.Server.Host.Components.Repository.Repository.libGitRepo
readonly LibGit2Sharp.IRepository libGitRepo
The LibGit2Sharp.IRepository for the Repository.
Definition: Repository.cs:83
Tgstation.Server.Host.Components.Repository.Repository.PushHeadToTemporaryBranch
Task PushHeadToTemporaryBranch(string username, string password, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Force push the current repository HEAD to RemoteTemporaryBranchName;.
Tgstation.Server.Host.Components.Repository.Repository.gitRemoteFeatures
readonly IGitRemoteFeatures gitRemoteFeatures
The IGitRemoteFeatures for the Repository.
Definition: Repository.cs:113
+
Tgstation.Server.Host.Components.Repository.Repository.UpdateSubmodules
ValueTask UpdateSubmodules(JobProgressReporter progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Recusively update all Submodules in the libGitRepo.
Definition: Repository.cs:1115
Tgstation.Server.Host.Components.Repository.Repository.submoduleFactory
readonly ILibGit2RepositoryFactory submoduleFactory
The ILibGit2RepositoryFactory used for updating submodules.
Definition: Repository.cs:118
-
Tgstation.Server.Host.Components.Repository.Repository.CheckoutObject
async ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
Checks out a given committish . A ValueTask representing the running operation.
Definition: Repository.cs:374
-
Tgstation.Server.Host.Components.Repository.Repository.GeneratePushOptions
PushOptions GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
Generate a standard set of PushOptions.
Definition: Repository.cs:1009
-
Tgstation.Server.Host.Components.Repository.Repository.MergeOrigin
async ValueTask< bool?> MergeOrigin(JobProgressReporter progressReporter, string committerName, string committerEmail, bool deploymentPipeline, CancellationToken cancellationToken)
Requires the current HEAD to be a tracked reference. Merges the reference to what it tracks on the or...
Definition: Repository.cs:551
-
Tgstation.Server.Host.Components.Repository.Repository.FetchOrigin
async ValueTask FetchOrigin(JobProgressReporter? progressReporter, string? username, string? password, bool deploymentPipeline, CancellationToken cancellationToken)
Fetch commits from the origin repository. A ValueTask representing the running operation.
Definition: Repository.cs:411
+
Tgstation.Server.Host.Components.Repository.Repository.MergeOrigin
async ValueTask< bool?> MergeOrigin(JobProgressReporter progressReporter, string committerName, string committerEmail, bool deploymentPipeline, CancellationToken cancellationToken)
Requires the current HEAD to be a tracked reference. Merges the reference to what it tracks on the or...
Definition: Repository.cs:564
Tgstation.Server.Host.Components.Repository.Repository.logger
readonly ILogger< Repository > logger
The ILogger for the Repository.
Definition: Repository.cs:123
-
Tgstation.Server.Host.Components.Repository.Repository.DisposeImpl
override void DisposeImpl()
Implementation of Dispose run after reentrancy check.
Definition: Repository.cs:873
+
Tgstation.Server.Host.Components.Repository.Repository.DisposeImpl
override void DisposeImpl()
Implementation of Dispose run after reentrancy check.
Definition: Repository.cs:899
Tgstation.Server.Host.Components.Repository.Repository.RemoteRepositoryOwner
string? RemoteRepositoryOwner
If RemoteGitProvider is not RemoteGitProvider.Unknown this will be set with the owner of the reposito...
Definition: Repository.cs:63
Tgstation.Server.Host.Components.Repository.Repository.ioManager
readonly IIOManager ioManager
The IIOManager for the Repository.
Definition: Repository.cs:93
Tgstation.Server.Host.Components.Repository.Repository.GetTestMerge
ValueTask< Models.TestMerge > GetTestMerge(TestMergeParameters parameters, RepositorySettings repositorySettings, CancellationToken cancellationToken)
Retrieve the Models.TestMerge representation of given test merge parameters . A ValueTask<TResult> re...
Tgstation.Server.Host.Components.Repository.Repository.postWriteHandler
readonly IPostWriteHandler postWriteHandler
The IPostWriteHandler for the Repository.
Definition: Repository.cs:108
Tgstation.Server.Host.Components.Repository.Repository.DefaultCommitterName
const string DefaultCommitterName
The default username for committers.
Definition: Repository.cs:32
Tgstation.Server.Host.Components.Repository.Repository.UnknownReference
const string UnknownReference
Used when a reference cannot be determined.
Definition: Repository.cs:57
-
Tgstation.Server.Host.Components.Repository.Repository.RawCheckout
void RawCheckout(string committish, bool moveCurrentReference, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
Runs a blocking force checkout to committish .
Definition: Repository.cs:887
Tgstation.Server.Host.Components.Repository.Repository.GetOriginSha
Task< string > GetOriginSha(CancellationToken cancellationToken)
Get the tracked reference's current SHA. A Task<TResult> resulting in the tracked origin reference's ...
Tgstation.Server.Host.Components.Repository.Repository.IsSha
Task< bool > IsSha(string committish, CancellationToken cancellationToken)
Checks if a given committish is a sha. A Task<TResult> resulting in true if committish is a sha,...
Tgstation.Server.Host.Components.Repository.Repository.CommittishIsParent
Task< bool > CommittishIsParent(string committish, CancellationToken cancellationToken)
Check if a given committish is a parent of the current Head. A Task<TResult> resulting in true if co...
@@ -1186,9 +1246,11 @@ $(function() {
Tgstation.Server.Host.Components.Repository.Repository.eventConsumer
readonly IEventConsumer eventConsumer
The IEventConsumer for the Repository.
Definition: Repository.cs:98
Tgstation.Server.Host.Components.Repository.Repository.NoReference
const string NoReference
The value of Reference when not on a reference.
Definition: Repository.cs:52
Tgstation.Server.Host.Components.Repository.Repository.CheckoutProgressHandler
CheckoutProgressHandler CheckoutProgressHandler(JobProgressReporter progressReporter)
Converts a given progressReporter to a LibGit2Sharp.Handlers.CheckoutProgressHandler.
+
Tgstation.Server.Host.Components.Repository.Repository.RawCheckout
void RawCheckout(string committish, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Runs a blocking force checkout to committish .
Definition: Repository.cs:913
Tgstation.Server.Host.Components.Repository.Repository.credentialsProvider
readonly ICredentialsProvider credentialsProvider
The ICredentialsProvider for the Repository.
Definition: Repository.cs:103
Tgstation.Server.Host.Components.Repository.Repository.TimestampCommit
Task< DateTimeOffset > TimestampCommit(string sha, CancellationToken cancellationToken)
Gets the DateTimeOffset a given sha was created on. A Task<TResult> resulting in the DateTimeOffset ...
-
Tgstation.Server.Host.Components.Repository.Repository.ResetToOrigin
async ValueTask ResetToOrigin(JobProgressReporter progressReporter, string? username, string? password, bool updateSubmodules, bool deploymentPipeline, CancellationToken cancellationToken)
Requires the current HEAD to be a tracked reference. Hard resets the reference to what it tracks on t...
Definition: Repository.cs:460
+
Tgstation.Server.Host.Components.Repository.Repository.ResetToOrigin
async ValueTask ResetToOrigin(JobProgressReporter progressReporter, string? username, string? password, bool updateSubmodules, bool deploymentPipeline, CancellationToken cancellationToken)
Requires the current HEAD to be a tracked reference. Hard resets the reference to what it tracks on t...
Definition: Repository.cs:468
+
Tgstation.Server.Host.Components.Repository.Repository.GeneratePushOptions
PushOptions IEnumerable< JobProgressReporter > SubProgressReporters GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
Definition: Repository.cs:1061
Tgstation.Server.Host.Components.Repository.Repository.generalConfiguration
readonly GeneralConfiguration generalConfiguration
The GeneralConfiguration for the Repository.
Definition: Repository.cs:128
Tgstation.Server.Host.Components.Repository.TestMergeResult
Represents the result of a repository test merge attempt.
Definition: TestMergeResult.cs:11
Tgstation.Server.Host.Components.Repository.TestMergeResult.Status
MergeStatus Status
The resulting MergeStatus.
Definition: TestMergeResult.cs:15
@@ -1196,9 +1258,9 @@ $(function() {
Tgstation.Server.Host.IO.DefaultIOManager
IIOManager that resolves paths to Environment.CurrentDirectory.
Definition: DefaultIOManager.cs:17
Tgstation.Server.Host.IO.DefaultIOManager.BlockingTaskCreationOptions
const TaskCreationOptions BlockingTaskCreationOptions
The TaskCreationOptions used to spawn Tasks for potentially long running, blocking operations.
Definition: DefaultIOManager.cs:31
Tgstation.Server.Host.Jobs.JobException
Operation exceptions thrown from the context of a Models.Job.
Definition: JobException.cs:11
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:100
-
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:74
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:176
+
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:137
Tgstation.Server.Host.Utils.DisposeInvoker
Runs a given disposeAction on Dispose.
Definition: DisposeInvoker.cs:10
Tgstation.Server.Host.Utils.DisposeInvoker.disposeAction
readonly Action disposeAction
The Action to run on Dispose.
Definition: DisposeInvoker.cs:19
Tgstation.Server.Api.Models.Internal.IGitRemoteInformation.RemoteRepositoryName
string? RemoteRepositoryName
If RemoteGitProvider is not RemoteGitProvider.Unknown this will be set with the name of the repositor...
Definition: IGitRemoteInformation.cs:21
diff --git a/_repository_manager_8cs_source.html b/_repository_manager_8cs_source.html index e4601fb08d..0b675a4e0a 100644 --- a/_repository_manager_8cs_source.html +++ b/_repository_manager_8cs_source.html @@ -150,12 +150,12 @@ $(function() {
117 semaphore.Dispose();
118 }
119
-
121 public async ValueTask<IRepository?> CloneRepository(
+
121 public async ValueTask<IRepository?> CloneRepository(
122 Uri url,
123 string? initialBranch,
124 string? username,
125 string? password,
-
126 JobProgressReporter? progressReporter,
+
126 JobProgressReporter progressReporter,
127 bool recurseSubmodules,
128 CancellationToken cancellationToken)
129 {
@@ -178,8 +178,8 @@ $(function() {
146 if (!await ioManager.DirectoryExists(repositoryPath, cancellationToken))
147 try
148 {
-
149 var cloneProgressReporter = progressReporter?.CreateSection(null, 0.75f);
-
150 var checkoutProgressReporter = progressReporter?.CreateSection(null, 0.25f);
+
149 using var cloneProgressReporter = progressReporter.CreateSection(null, 0.75f);
+
150 using var checkoutProgressReporter = progressReporter.CreateSection(null, 0.25f);
151 var cloneOptions = new CloneOptions
152 {
153 RecurseSubmodules = recurseSubmodules,
@@ -307,7 +307,6 @@ $(function() {
Tgstation.Server.Host.Components.Repository.Repository
Definition: Repository.cs:28
Tgstation.Server.Host.Components.Repository.RepositoryManager
Definition: RepositoryManager.cs:21
Tgstation.Server.Host.Components.Repository.RepositoryManager.RepositoryManager
RepositoryManager(ILibGit2RepositoryFactory repositoryFactory, ILibGit2Commands commands, IIOManager ioManager, IEventConsumer eventConsumer, IPostWriteHandler postWriteHandler, IGitRemoteFeaturesFactory gitRemoteFeaturesFactory, ILogger< Repository > repositoryLogger, ILogger< RepositoryManager > logger, GeneralConfiguration generalConfiguration)
Initializes a new instance of the RepositoryManager class.
Definition: RepositoryManager.cs:90
-
Tgstation.Server.Host.Components.Repository.RepositoryManager.CloneRepository
async ValueTask< IRepository?> CloneRepository(Uri url, string? initialBranch, string? username, string? password, JobProgressReporter? progressReporter, bool recurseSubmodules, CancellationToken cancellationToken)
Clone the repository at url . A ValueTask<TResult> resulting i the newly cloned IRepository,...
Definition: RepositoryManager.cs:121
Tgstation.Server.Host.Components.Repository.RepositoryManager.repositoryLogger
readonly ILogger< Repository > repositoryLogger
The ILogger created Repositorys.
Definition: RepositoryManager.cs:61
Tgstation.Server.Host.Components.Repository.RepositoryManager.DeleteRepository
async ValueTask DeleteRepository(CancellationToken cancellationToken)
Delete the current repository. A ValueTask representing the running operation.
Definition: RepositoryManager.cs:258
Tgstation.Server.Host.Components.Repository.RepositoryManager.generalConfiguration
readonly GeneralConfiguration generalConfiguration
The GeneralConfiguration for the RepositoryManager.
Definition: RepositoryManager.cs:71
@@ -319,15 +318,16 @@ $(function() {
Tgstation.Server.Host.Components.Repository.RepositoryManager.InUse
bool InUse
If something is holding a lock on the repository.
Definition: RepositoryManager.cs:23
Tgstation.Server.Host.Components.Repository.RepositoryManager.postWriteHandler
readonly IPostWriteHandler postWriteHandler
The IPostWriteHandler for the RepositoryManager.
Definition: RepositoryManager.cs:51
Tgstation.Server.Host.Components.Repository.RepositoryManager.ioManager
readonly IIOManager ioManager
The IIOManager for the RepositoryManager.
Definition: RepositoryManager.cs:41
+
Tgstation.Server.Host.Components.Repository.RepositoryManager.CloneRepository
async ValueTask< IRepository?> CloneRepository(Uri url, string? initialBranch, string? username, string? password, JobProgressReporter progressReporter, bool recurseSubmodules, CancellationToken cancellationToken)
Clone the repository at url . A ValueTask<TResult> resulting i the newly cloned IRepository,...
Definition: RepositoryManager.cs:121
Tgstation.Server.Host.Components.Repository.RepositoryManager.logger
readonly ILogger< RepositoryManager > logger
The ILogger for the RepositoryManager.
Definition: RepositoryManager.cs:66
Tgstation.Server.Host.Components.Repository.RepositoryManager.eventConsumer
readonly IEventConsumer eventConsumer
The IEventConsumer for the RepositoryManager.
Definition: RepositoryManager.cs:46
Tgstation.Server.Host.Components.Repository.RepositoryManager.CloneInProgress
bool CloneInProgress
If a CloneRepository(Uri, string, string, string, JobProgressReporter, bool, CancellationToken) opera...
Definition: RepositoryManager.cs:26
Tgstation.Server.Host.Components.Repository.RepositoryManager.gitRemoteFeaturesFactory
readonly IGitRemoteFeaturesFactory gitRemoteFeaturesFactory
The IGitRemoteFeaturesFactory for the RepositoryManager.
Definition: RepositoryManager.cs:56
Tgstation.Server.Host.Configuration.GeneralConfiguration
General configuration options.
Definition: GeneralConfiguration.cs:20
Tgstation.Server.Host.Jobs.JobException
Operation exceptions thrown from the context of a Models.Job.
Definition: JobException.cs:11
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:100
-
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:74
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:176
+
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:137
Tgstation.Server.Host.Utils.SemaphoreSlimContext
Async lock context helper.
Definition: SemaphoreSlimContext.cs:11
Tgstation.Server.Host.Utils.SemaphoreSlimContext.Lock
static async ValueTask< SemaphoreSlimContext > Lock(SemaphoreSlim semaphore, CancellationToken cancellationToken)
Asyncronously locks a semaphore .
Definition: SemaphoreSlimContext.cs:18
Tgstation.Server.Host.Components.Events.IEventConsumer
Consumes EventTypes and takes the appropriate actions.
Definition: IEventConsumer.cs:11
diff --git a/_repository_update_service_8cs_source.html b/_repository_update_service_8cs_source.html index 0504c7fc61..fbbfbe87ed 100644 --- a/_repository_update_service_8cs_source.html +++ b/_repository_update_service_8cs_source.html @@ -210,491 +210,512 @@ $(function() {
173 var numSteps = (model.NewTestMerges?.Count ?? 0) + (model.UpdateFromOrigin == true ? 1 : 0) + (!modelHasShaOrReference ? 2 : (hardResettingToOriginReference ? 3 : 1));
174 var progressFactor = 1.0 / numSteps;
175
-
176 JobProgressReporter NextProgressReporter(string? stage)
-
177 {
-
178 return progressReporter.CreateSection(stage, progressFactor);
-
179 }
-
180
-
181 progressReporter.ReportProgress(0);
+
176 JobProgressReporter NextProgressReporter(string? stage) => progressReporter.CreateSection(stage, progressFactor);
+
177
+
178 progressReporter.ReportProgress(0);
+
179
+
180 // get a base line for where we are
+
181 Models.RevisionInformation? lastRevisionInfo = null;
182
-
183 // get a base line for where we are
-
184 Models.RevisionInformation? lastRevisionInfo = null;
-
185
-
186 var attachedInstance = new Models.Instance
-
187 {
-
188 Id = instanceId,
-
189 };
-
190
-
191 ValueTask CallLoadRevInfo(Models.TestMerge? testMergeToAdd = null, string? lastOriginCommitSha = null) => databaseContextFactory
-
192 .UseContext(
-
193 async databaseContext =>
-
194 {
-
195 databaseContext.Instances.Attach(attachedInstance);
-
196 var previousRevInfo = lastRevisionInfo!;
-
197 var needsUpdate = await LoadRevisionInformation(
-
198 repo,
-
199 databaseContext,
-
200 logger,
-
201 attachedInstance,
-
202 lastOriginCommitSha,
-
203 x => lastRevisionInfo = x,
-
204 cancellationToken);
-
205
-
206 if (testMergeToAdd != null)
-
207 {
-
208 // rev info may have already loaded the user
-
209 var mergedBy = databaseContext.Users.Local.FirstOrDefault(x => x.Id == initiatingUser.Id);
-
210 if (mergedBy == default)
-
211 {
-
212 mergedBy = new User
-
213 {
-
214 Id = initiatingUser.Id,
-
215 };
+
183 var attachedInstance = new Models.Instance
+
184 {
+
185 Id = instanceId,
+
186 };
+
187
+
188 ValueTask CallLoadRevInfo(Models.TestMerge? testMergeToAdd = null, string? lastOriginCommitSha = null) => databaseContextFactory
+
189 .UseContext(
+
190 async databaseContext =>
+
191 {
+
192 databaseContext.Instances.Attach(attachedInstance);
+
193 var previousRevInfo = lastRevisionInfo!;
+
194 var needsUpdate = await LoadRevisionInformation(
+
195 repo,
+
196 databaseContext,
+
197 logger,
+
198 attachedInstance,
+
199 lastOriginCommitSha,
+
200 x => lastRevisionInfo = x,
+
201 cancellationToken);
+
202
+
203 if (testMergeToAdd != null)
+
204 {
+
205 // rev info may have already loaded the user
+
206 var mergedBy = databaseContext.Users.Local.FirstOrDefault(x => x.Id == initiatingUser.Id);
+
207 if (mergedBy == default)
+
208 {
+
209 mergedBy = new User
+
210 {
+
211 Id = initiatingUser.Id,
+
212 };
+
213
+
214 databaseContext.Users.Attach(mergedBy);
+
215 }
216
-
217 databaseContext.Users.Attach(mergedBy);
-
218 }
+
217 testMergeToAdd.MergedBy = mergedBy;
+
218 testMergeToAdd.MergedAt = DateTimeOffset.UtcNow;
219
-
220 testMergeToAdd.MergedBy = mergedBy;
-
221 testMergeToAdd.MergedAt = DateTimeOffset.UtcNow;
-
222
-
223 var activeTestMerges = lastRevisionInfo!.ActiveTestMerges!;
-
224 foreach (var activeTestMerge in previousRevInfo.ActiveTestMerges!)
-
225 activeTestMerges.Add(activeTestMerge);
+
220 var activeTestMerges = lastRevisionInfo!.ActiveTestMerges!;
+
221 foreach (var activeTestMerge in previousRevInfo.ActiveTestMerges!)
+
222 activeTestMerges.Add(activeTestMerge);
+
223
+
224 activeTestMerges.Add(new RevInfoTestMerge(testMergeToAdd, lastRevisionInfo));
+
225 lastRevisionInfo.PrimaryTestMerge = testMergeToAdd;
226
-
227 activeTestMerges.Add(new RevInfoTestMerge(testMergeToAdd, lastRevisionInfo));
-
228 lastRevisionInfo.PrimaryTestMerge = testMergeToAdd;
+
227 needsUpdate = true;
+
228 }
229
-
230 needsUpdate = true;
-
231 }
-
232
-
233 if (needsUpdate)
-
234 await databaseContext.Save(cancellationToken);
-
235 });
-
236
-
237 await CallLoadRevInfo();
+
230 if (needsUpdate)
+
231 await databaseContext.Save(cancellationToken);
+
232 });
+
233
+
234 await CallLoadRevInfo();
+
235
+
236 // apply new rev info, tracking applied test merges
+
237 ValueTask UpdateRevInfo(Models.TestMerge? testMergeToAdd = null) => CallLoadRevInfo(testMergeToAdd, lastRevisionInfo!.OriginCommitSha);
238
-
239 // apply new rev info, tracking applied test merges
-
240 ValueTask UpdateRevInfo(Models.TestMerge? testMergeToAdd = null) => CallLoadRevInfo(testMergeToAdd, lastRevisionInfo!.OriginCommitSha);
-
241
-
242 try
-
243 {
-
244 // fetch/pull
-
245 if (model.UpdateFromOrigin == true)
-
246 {
-
247 if (!repo.Tracking)
-
248 throw new JobException(ErrorCode.RepoReferenceRequired);
-
249 await repo.FetchOrigin(
-
250 NextProgressReporter("Fetch Origin"),
-
251 currentModel.AccessUser,
-
252 currentModel.AccessToken,
-
253 false,
-
254 cancellationToken);
-
255
-
256 if (!modelHasShaOrReference)
-
257 {
-
258 var fastForward = await repo.MergeOrigin(
-
259 NextProgressReporter("Merge Origin"),
-
260 committerName,
-
261 currentModel.CommitterEmail!,
-
262 false,
-
263 cancellationToken);
-
264 if (!fastForward.HasValue)
-
265 throw new JobException(ErrorCode.RepoMergeConflict);
-
266 lastRevisionInfo!.OriginCommitSha = await repo.GetOriginSha(cancellationToken);
-
267 await UpdateRevInfo();
-
268 if (fastForward.Value)
-
269 {
-
270 await repo.Synchronize(
-
271 NextProgressReporter("Sychronize"),
-
272 currentModel.AccessUser,
-
273 currentModel.AccessToken,
-
274 currentModel.CommitterName!,
-
275 currentModel.CommitterEmail!,
-
276 true,
-
277 false,
-
278 cancellationToken);
-
279 postUpdateSha = repo.Head;
-
280 }
-
281 else
-
282 NextProgressReporter(null).ReportProgress(1.0);
-
283 }
-
284 }
-
285
-
286 var updateSubmodules = currentModel.UpdateSubmodules!.Value;
-
287
-
288 // checkout/hard reset
-
289 if (modelHasShaOrReference)
-
290 {
-
291 var validCheckoutSha =
-
292 model.CheckoutSha != null
-
293 && !repo.Head.StartsWith(model.CheckoutSha, StringComparison.OrdinalIgnoreCase);
-
294 var validCheckoutReference =
-
295 model.Reference != null
-
296 && !repo.Reference.Equals(model.Reference, StringComparison.OrdinalIgnoreCase);
-
297
-
298 if (validCheckoutSha || validCheckoutReference)
-
299 {
-
300 var committish = model.CheckoutSha ?? model.Reference!;
-
301 var isSha = await repo.IsSha(committish, cancellationToken);
-
302
-
303 if ((isSha && model.Reference != null) || (!isSha && model.CheckoutSha != null))
-
304 throw new JobException(ErrorCode.RepoSwappedShaOrReference);
+
239 try
+
240 {
+
241 // fetch/pull
+
242 if (model.UpdateFromOrigin == true)
+
243 {
+
244 if (!repo.Tracking)
+
245 throw new JobException(ErrorCode.RepoReferenceRequired);
+
246 using (var fetchReporter = NextProgressReporter("Fetch Origin"))
+
247 await repo.FetchOrigin(
+
248 fetchReporter,
+
249 currentModel.AccessUser,
+
250 currentModel.AccessToken,
+
251 false,
+
252 cancellationToken);
+
253
+
254 if (!modelHasShaOrReference)
+
255 {
+
256 bool? fastForward;
+
257 using (var mergeReporter = NextProgressReporter("Merge Origin"))
+
258 fastForward = await repo.MergeOrigin(
+
259 mergeReporter,
+
260 committerName,
+
261 currentModel.CommitterEmail!,
+
262 false,
+
263 cancellationToken);
+
264
+
265 if (!fastForward.HasValue)
+
266 throw new JobException(ErrorCode.RepoMergeConflict);
+
267
+
268 lastRevisionInfo!.OriginCommitSha = await repo.GetOriginSha(cancellationToken);
+
269 await UpdateRevInfo();
+
270 if (fastForward.Value)
+
271 {
+
272 using var syncReporter = NextProgressReporter("Sychronize");
+
273 await repo.Synchronize(
+
274 syncReporter,
+
275 currentModel.AccessUser,
+
276 currentModel.AccessToken,
+
277 currentModel.CommitterName!,
+
278 currentModel.CommitterEmail!,
+
279 true,
+
280 false,
+
281 cancellationToken);
+
282 postUpdateSha = repo.Head;
+
283 }
+
284 else
+
285 NextProgressReporter(null).Dispose();
+
286 }
+
287 }
+
288
+
289 var updateSubmodules = currentModel.UpdateSubmodules!.Value;
+
290
+
291 // checkout/hard reset
+
292 if (modelHasShaOrReference)
+
293 {
+
294 var validCheckoutSha =
+
295 model.CheckoutSha != null
+
296 && !repo.Head.StartsWith(model.CheckoutSha, StringComparison.OrdinalIgnoreCase);
+
297 var validCheckoutReference =
+
298 model.Reference != null
+
299 && !repo.Reference.Equals(model.Reference, StringComparison.OrdinalIgnoreCase);
+
300
+
301 if (validCheckoutSha || validCheckoutReference)
+
302 {
+
303 var committish = model.CheckoutSha ?? model.Reference!;
+
304 var isSha = await repo.IsSha(committish, cancellationToken);
305
-
306 await repo.CheckoutObject(
-
307 committish,
-
308 currentModel.AccessUser,
-
309 currentModel.AccessToken,
-
310 updateSubmodules,
-
311 false,
-
312 NextProgressReporter("Checkout"),
-
313 cancellationToken);
-
314 await CallLoadRevInfo(); // we've either seen origin before or what we're checking out is on origin
-
315 }
-
316 else
-
317 NextProgressReporter(null).ReportProgress(1.0);
-
318
-
319 if (hardResettingToOriginReference)
-
320 {
-
321 if (!repo.Tracking)
-
322 throw new JobException(ErrorCode.RepoReferenceNotTracking);
-
323 await repo.ResetToOrigin(
-
324 NextProgressReporter("Reset to Origin"),
-
325 currentModel.AccessUser,
-
326 currentModel.AccessToken,
-
327 updateSubmodules,
-
328 false,
-
329 cancellationToken);
-
330 await repo.Synchronize(
-
331 NextProgressReporter("Synchronize"),
-
332 currentModel.AccessUser,
-
333 currentModel.AccessToken,
-
334 currentModel.CommitterName!,
-
335 currentModel.CommitterEmail!,
-
336 true,
-
337 false,
-
338 cancellationToken);
-
339 await CallLoadRevInfo();
-
340
-
341 // repo head is on origin so force this
-
342 // will update the db if necessary
-
343 lastRevisionInfo!.OriginCommitSha = repo.Head;
-
344 }
-
345 }
+
306 if ((isSha && model.Reference != null) || (!isSha && model.CheckoutSha != null))
+
307 throw new JobException(ErrorCode.RepoSwappedShaOrReference);
+
308
+
309 using (var checkoutReporter = NextProgressReporter("Checkout"))
+
310 await repo.CheckoutObject(
+
311 committish,
+
312 currentModel.AccessUser,
+
313 currentModel.AccessToken,
+
314 updateSubmodules,
+
315 false,
+
316 checkoutReporter,
+
317 cancellationToken);
+
318 await CallLoadRevInfo(); // we've either seen origin before or what we're checking out is on origin
+
319 }
+
320 else
+
321 NextProgressReporter(null).Dispose();
+
322
+
323 if (hardResettingToOriginReference)
+
324 {
+
325 if (!repo.Tracking)
+
326 throw new JobException(ErrorCode.RepoReferenceNotTracking);
+
327 using (var resetReporter = NextProgressReporter("Reset to Origin"))
+
328 await repo.ResetToOrigin(
+
329 resetReporter,
+
330 currentModel.AccessUser,
+
331 currentModel.AccessToken,
+
332 updateSubmodules,
+
333 false,
+
334 cancellationToken);
+
335
+
336 using (var syncReporter = NextProgressReporter("Synchronize"))
+
337 await repo.Synchronize(
+
338 syncReporter,
+
339 currentModel.AccessUser,
+
340 currentModel.AccessToken,
+
341 currentModel.CommitterName!,
+
342 currentModel.CommitterEmail!,
+
343 true,
+
344 false,
+
345 cancellationToken);
346
-
347 // test merging
-
348 if (newTestMerges)
-
349 {
-
350 if (repo.RemoteGitProvider == RemoteGitProvider.Unknown)
-
351 throw new JobException(ErrorCode.RepoTestMergeInvalidRemote);
-
352
-
353 // bit of sanitization
-
354 var newTestMergeModels = model.NewTestMerges!;
-
355 foreach (var newTestMergeWithoutTargetCommitSha in newTestMergeModels.Where(x => String.IsNullOrWhiteSpace(x.TargetCommitSha)))
-
356 newTestMergeWithoutTargetCommitSha.TargetCommitSha = null;
-
357
-
358 var repoOwner = repo.RemoteRepositoryOwner;
-
359 var repoName = repo.RemoteRepositoryName;
+
347 await CallLoadRevInfo();
+
348
+
349 // repo head is on origin so force this
+
350 // will update the db if necessary
+
351 lastRevisionInfo!.OriginCommitSha = repo.Head;
+
352 }
+
353 }
+
354
+
355 // test merging
+
356 if (newTestMerges)
+
357 {
+
358 if (repo.RemoteGitProvider == RemoteGitProvider.Unknown)
+
359 throw new JobException(ErrorCode.RepoTestMergeInvalidRemote);
360
-
361 // optimization: if we've already merged these exact same commits in this fashion before, just find the rev info for it and check it out
-
362 Models.RevisionInformation? revInfoWereLookingFor = null;
-
363 bool needToApplyRemainingPrs = true;
-
364 if (lastRevisionInfo!.OriginCommitSha == lastRevisionInfo.CommitSha)
-
365 {
-
366 bool cantSearch = false;
-
367 foreach (var newTestMerge in newTestMergeModels)
-
368 {
-
369 if (newTestMerge.TargetCommitSha != null)
-
370#pragma warning disable CA1308 // Normalize strings to uppercase
-
371 newTestMerge.TargetCommitSha = newTestMerge.TargetCommitSha?.ToLowerInvariant(); // ala libgit2
-
372#pragma warning restore CA1308 // Normalize strings to uppercase
-
373 else
-
374 try
-
375 {
-
376 // retrieve the latest sha
-
377 var pr = await repo.GetTestMerge(newTestMerge, currentModel, cancellationToken);
-
378
-
379 // we want to take the earliest truth possible to prevent RCEs, if this fails AddTestMerge will set it
-
380 newTestMerge.TargetCommitSha = pr.TargetCommitSha;
-
381 }
-
382 catch
+
361 // bit of sanitization
+
362 var newTestMergeModels = model.NewTestMerges!;
+
363 foreach (var newTestMergeWithoutTargetCommitSha in newTestMergeModels.Where(x => String.IsNullOrWhiteSpace(x.TargetCommitSha)))
+
364 newTestMergeWithoutTargetCommitSha.TargetCommitSha = null;
+
365
+
366 var repoOwner = repo.RemoteRepositoryOwner;
+
367 var repoName = repo.RemoteRepositoryName;
+
368
+
369 // optimization: if we've already merged these exact same commits in this fashion before, just find the rev info for it and check it out
+
370 Models.RevisionInformation? revInfoWereLookingFor = null;
+
371 bool needToApplyRemainingPrs = true;
+
372 if (lastRevisionInfo!.OriginCommitSha == lastRevisionInfo.CommitSha)
+
373 {
+
374 bool cantSearch = false;
+
375 foreach (var newTestMerge in newTestMergeModels)
+
376 {
+
377 if (newTestMerge.TargetCommitSha != null)
+
378#pragma warning disable CA1308 // Normalize strings to uppercase
+
379 newTestMerge.TargetCommitSha = newTestMerge.TargetCommitSha?.ToLowerInvariant(); // ala libgit2
+
380#pragma warning restore CA1308 // Normalize strings to uppercase
+
381 else
+
382 try
383 {
-
384 cantSearch = true;
-
385 break;
-
386 }
-
387 }
-
388
-
389 if (!cantSearch)
-
390 {
-
391 List<Models.RevisionInformation>? dbPull = null;
-
392
-
393 await databaseContextFactory.UseContext(
-
394 async databaseContext =>
-
395 dbPull = await databaseContext.RevisionInformations
-
396 .AsQueryable()
-
397 .Where(x => x.InstanceId == instanceId
-
398 && x.OriginCommitSha == lastRevisionInfo.OriginCommitSha
-
399 && x.ActiveTestMerges!.Count <= newTestMergeModels.Count
-
400 && x.ActiveTestMerges!.Count > 0)
-
401 .Include(x => x.ActiveTestMerges!)
-
402 .ThenInclude(x => x.TestMerge)
-
403 .ToListAsync(cancellationToken));
-
404
-
405 // split here cause this bit has to be done locally
-
406 revInfoWereLookingFor = dbPull!
-
407 .Where(x => x.ActiveTestMerges!.Count == newTestMergeModels.Count
-
408 && x.ActiveTestMerges
-
409 .Select(y => y.TestMerge)
-
410 .All(y => newTestMergeModels
-
411 .Any(z =>
-
412 y.Number == z.Number
-
413 && y.TargetCommitSha!.StartsWith(z.TargetCommitSha!, StringComparison.Ordinal)
-
414 && (y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))))
-
415 .FirstOrDefault();
-
416
-
417 if (revInfoWereLookingFor == default && newTestMergeModels.Count > 1)
-
418 {
-
419 // okay try to add at least SOME prs we've seen before
-
420 var listedNewTestMerges = newTestMergeModels.ToList();
-
421
-
422 var appliedTestMergeIds = new List<long>();
-
423
-
424 Models.RevisionInformation? lastGoodRevInfo = null;
-
425 do
-
426 {
-
427 foreach (var newTestMergeParameters in listedNewTestMerges)
-
428 {
-
429 revInfoWereLookingFor = dbPull!
-
430 .Where(testRevInfo =>
-
431 {
-
432 if (testRevInfo.PrimaryTestMerge == null)
-
433 return false;
-
434
-
435 var testMergeMatch = newTestMergeModels.Any(testTestMerge =>
-
436 {
-
437 var numberMatch = testRevInfo.PrimaryTestMerge.Number == testTestMerge.Number;
-
438 if (!numberMatch)
-
439 return false;
-
440
-
441 var shaMatch = testRevInfo.PrimaryTestMerge.TargetCommitSha!.StartsWith(
-
442 testTestMerge.TargetCommitSha!,
-
443 StringComparison.Ordinal);
-
444 if (!shaMatch)
-
445 return false;
-
446
-
447 var commentMatch = testRevInfo.PrimaryTestMerge.Comment == testTestMerge.Comment;
-
448 return commentMatch;
-
449 });
-
450
-
451 if (!testMergeMatch)
-
452 return false;
-
453
-
454 var previousTestMergesMatch = testRevInfo
-
455 .ActiveTestMerges!
-
456 .Select(previousRevInfoTestMerge => previousRevInfoTestMerge.TestMerge)
-
457 .All(previousTestMerge => appliedTestMergeIds.Contains(previousTestMerge.Id));
+
384 // retrieve the latest sha
+
385 var pr = await repo.GetTestMerge(newTestMerge, currentModel, cancellationToken);
+
386
+
387 // we want to take the earliest truth possible to prevent RCEs, if this fails AddTestMerge will set it
+
388 newTestMerge.TargetCommitSha = pr.TargetCommitSha;
+
389 }
+
390 catch
+
391 {
+
392 cantSearch = true;
+
393 break;
+
394 }
+
395 }
+
396
+
397 if (!cantSearch)
+
398 {
+
399 List<Models.RevisionInformation>? dbPull = null;
+
400
+
401 await databaseContextFactory.UseContext(
+
402 async databaseContext =>
+
403 dbPull = await databaseContext.RevisionInformations
+
404 .AsQueryable()
+
405 .Where(x => x.InstanceId == instanceId
+
406 && x.OriginCommitSha == lastRevisionInfo.OriginCommitSha
+
407 && x.ActiveTestMerges!.Count <= newTestMergeModels.Count
+
408 && x.ActiveTestMerges!.Count > 0)
+
409 .Include(x => x.ActiveTestMerges!)
+
410 .ThenInclude(x => x.TestMerge)
+
411 .ToListAsync(cancellationToken));
+
412
+
413 // split here cause this bit has to be done locally
+
414 revInfoWereLookingFor = dbPull!
+
415 .Where(x => x.ActiveTestMerges!.Count == newTestMergeModels.Count
+
416 && x.ActiveTestMerges
+
417 .Select(y => y.TestMerge)
+
418 .All(y => newTestMergeModels
+
419 .Any(z =>
+
420 y.Number == z.Number
+
421 && y.TargetCommitSha!.StartsWith(z.TargetCommitSha!, StringComparison.Ordinal)
+
422 && (y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null))))
+
423 .FirstOrDefault();
+
424
+
425 if (revInfoWereLookingFor == default && newTestMergeModels.Count > 1)
+
426 {
+
427 // okay try to add at least SOME prs we've seen before
+
428 var listedNewTestMerges = newTestMergeModels.ToList();
+
429
+
430 var appliedTestMergeIds = new List<long>();
+
431
+
432 Models.RevisionInformation? lastGoodRevInfo = null;
+
433 do
+
434 {
+
435 foreach (var newTestMergeParameters in listedNewTestMerges)
+
436 {
+
437 revInfoWereLookingFor = dbPull!
+
438 .Where(testRevInfo =>
+
439 {
+
440 if (testRevInfo.PrimaryTestMerge == null)
+
441 return false;
+
442
+
443 var testMergeMatch = newTestMergeModels.Any(testTestMerge =>
+
444 {
+
445 var numberMatch = testRevInfo.PrimaryTestMerge.Number == testTestMerge.Number;
+
446 if (!numberMatch)
+
447 return false;
+
448
+
449 var shaMatch = testRevInfo.PrimaryTestMerge.TargetCommitSha!.StartsWith(
+
450 testTestMerge.TargetCommitSha!,
+
451 StringComparison.Ordinal);
+
452 if (!shaMatch)
+
453 return false;
+
454
+
455 var commentMatch = testRevInfo.PrimaryTestMerge.Comment == testTestMerge.Comment;
+
456 return commentMatch;
+
457 });
458
-
459 return previousTestMergesMatch;
-
460 })
-
461 .FirstOrDefault();
-
462
-
463 if (revInfoWereLookingFor != null)
-
464 {
-
465 lastGoodRevInfo = revInfoWereLookingFor;
-
466 appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge!.Id);
-
467 listedNewTestMerges.Remove(newTestMergeParameters);
-
468 break;
-
469 }
-
470 }
-
471 }
-
472 while (revInfoWereLookingFor != null && listedNewTestMerges.Count > 0);
-
473
-
474 revInfoWereLookingFor = lastGoodRevInfo;
-
475 needToApplyRemainingPrs = listedNewTestMerges.Count != 0;
-
476 if (needToApplyRemainingPrs)
-
477 model.NewTestMerges = listedNewTestMerges;
-
478 }
-
479 else if (revInfoWereLookingFor != null)
-
480 needToApplyRemainingPrs = false;
-
481 }
-
482 }
-
483
-
484 if (revInfoWereLookingFor != null)
-
485 {
-
486 // goteem
-
487 var commitSha = revInfoWereLookingFor.CommitSha!;
-
488 logger.LogDebug("Reusing existing SHA {sha}...", commitSha);
-
489 await repo.ResetToSha(commitSha, NextProgressReporter($"Reset to {commitSha[..7]}"), cancellationToken);
-
490 lastRevisionInfo = revInfoWereLookingFor;
-
491 }
-
492
-
493 if (needToApplyRemainingPrs)
-
494 {
-
495 foreach (var newTestMerge in newTestMergeModels)
-
496 {
-
497 if (lastRevisionInfo.ActiveTestMerges!.Any(x => x.TestMerge.Number == newTestMerge.Number))
-
498 throw new JobException(ErrorCode.RepoDuplicateTestMerge);
-
499
-
500 var fullTestMergeTask = repo.GetTestMerge(newTestMerge, currentModel, cancellationToken);
+
459 if (!testMergeMatch)
+
460 return false;
+
461
+
462 var previousTestMergesMatch = testRevInfo
+
463 .ActiveTestMerges!
+
464 .Select(previousRevInfoTestMerge => previousRevInfoTestMerge.TestMerge)
+
465 .All(previousTestMerge => appliedTestMergeIds.Contains(previousTestMerge.Id));
+
466
+
467 return previousTestMergesMatch;
+
468 })
+
469 .FirstOrDefault();
+
470
+
471 if (revInfoWereLookingFor != null)
+
472 {
+
473 lastGoodRevInfo = revInfoWereLookingFor;
+
474 appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge!.Id);
+
475 listedNewTestMerges.Remove(newTestMergeParameters);
+
476 break;
+
477 }
+
478 }
+
479 }
+
480 while (revInfoWereLookingFor != null && listedNewTestMerges.Count > 0);
+
481
+
482 revInfoWereLookingFor = lastGoodRevInfo;
+
483 needToApplyRemainingPrs = listedNewTestMerges.Count != 0;
+
484 if (needToApplyRemainingPrs)
+
485 model.NewTestMerges = listedNewTestMerges;
+
486 }
+
487 else if (revInfoWereLookingFor != null)
+
488 needToApplyRemainingPrs = false;
+
489 }
+
490 }
+
491
+
492 if (revInfoWereLookingFor != null)
+
493 {
+
494 // goteem
+
495 var commitSha = revInfoWereLookingFor.CommitSha!;
+
496 logger.LogDebug("Reusing existing SHA {sha}...", commitSha);
+
497 using var resetReporter = NextProgressReporter($"Reset to {commitSha[..7]}");
+
498 await repo.ResetToSha(commitSha, resetReporter, cancellationToken);
+
499 lastRevisionInfo = revInfoWereLookingFor;
+
500 }
501
-
502 var mergeResult = await repo.AddTestMerge(
-
503 newTestMerge,
-
504 committerName,
-
505 currentModel.CommitterEmail!,
-
506 currentModel.AccessUser,
-
507 currentModel.AccessToken,
-
508 updateSubmodules,
-
509 NextProgressReporter($"Test merge #{newTestMerge.Number}"),
-
510 cancellationToken);
-
511
-
512 if (mergeResult.Status == MergeStatus.Conflicts)
-
513 throw new JobException(
-
514 ErrorCode.RepoTestMergeConflict,
-
515 new JobException(
-
516 $"Test Merge #{newTestMerge.Number} at {newTestMerge.TargetCommitSha![..7]} conflicted! Conflicting files:{Environment.NewLine}{String.Join(Environment.NewLine, mergeResult.ConflictingFiles!.Select(file => $"\t- /{file}"))}"));
-
517
-
518 Models.TestMerge fullTestMerge;
-
519 try
-
520 {
-
521 fullTestMerge = await fullTestMergeTask;
-
522 }
-
523 catch (Exception ex)
-
524 {
-
525 logger.LogWarning("Error retrieving metadata for test merge #{testMergeNumber}!", newTestMerge.Number);
-
526
-
527 fullTestMerge = new Models.TestMerge
-
528 {
-
529 Author = ex.Message,
-
530 BodyAtMerge = ex.Message,
-
531 TitleAtMerge = ex.Message,
-
532 Comment = newTestMerge.Comment,
-
533 Number = newTestMerge.Number,
-
534 Url = ex.Message,
-
535 };
-
536 }
+
502 if (needToApplyRemainingPrs)
+
503 {
+
504 foreach (var newTestMerge in newTestMergeModels)
+
505 {
+
506 if (lastRevisionInfo.ActiveTestMerges!.Any(x => x.TestMerge.Number == newTestMerge.Number))
+
507 throw new JobException(ErrorCode.RepoDuplicateTestMerge);
+
508
+
509 var fullTestMergeTask = repo.GetTestMerge(newTestMerge, currentModel, cancellationToken);
+
510
+
511 TestMergeResult mergeResult;
+
512 using (var testMergeReporter = NextProgressReporter($"Test merge #{newTestMerge.Number}"))
+
513 mergeResult = await repo.AddTestMerge(
+
514 newTestMerge,
+
515 committerName,
+
516 currentModel.CommitterEmail!,
+
517 currentModel.AccessUser,
+
518 currentModel.AccessToken,
+
519 updateSubmodules,
+
520 testMergeReporter,
+
521 cancellationToken);
+
522
+
523 if (mergeResult.Status == MergeStatus.Conflicts)
+
524 throw new JobException(
+
525 ErrorCode.RepoTestMergeConflict,
+
526 new JobException(
+
527 $"Test Merge #{newTestMerge.Number} at {newTestMerge.TargetCommitSha![..7]} conflicted! Conflicting files:{Environment.NewLine}{String.Join(Environment.NewLine, mergeResult.ConflictingFiles!.Select(file => $"\t- /{file}"))}"));
+
528
+
529 Models.TestMerge fullTestMerge;
+
530 try
+
531 {
+
532 fullTestMerge = await fullTestMergeTask;
+
533 }
+
534 catch (Exception ex)
+
535 {
+
536 logger.LogWarning("Error retrieving metadata for test merge #{testMergeNumber}!", newTestMerge.Number);
537
-
538 // Ensure we're getting the full sha from git itself
-
539 fullTestMerge.TargetCommitSha = newTestMerge.TargetCommitSha;
-
540
-
541 await UpdateRevInfo(fullTestMerge);
-
542 }
-
543 }
-
544 }
-
545
-
546 var currentHead = repo.Head;
-
547 if (currentModel.PushTestMergeCommits!.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead)))
-
548 {
-
549 await repo.Synchronize(
-
550 NextProgressReporter("Synchronize"),
-
551 currentModel.AccessUser,
-
552 currentModel.AccessToken,
-
553 currentModel.CommitterName!,
-
554 currentModel.CommitterEmail!,
-
555 false,
-
556 false,
-
557 cancellationToken);
-
558 await UpdateRevInfo();
-
559 }
-
560 }
-
561 catch
-
562 {
-
563 numSteps = 2;
-
564
-
565 // Forget what we've done and abort
-
566 progressReporter.ReportProgress(0.0);
-
567
-
568 var secondStep = startReference != null && repo.Head != startSha;
-
569
-
570 // DCTx2: Cancellation token is for job, operations should always run
-
571 await repo.CheckoutObject(
-
572 startReference ?? startSha,
-
573 currentModel.AccessUser,
-
574 currentModel.AccessToken,
-
575 true,
-
576 false,
-
577 progressReporter.CreateSection($"Checkout {startReference ?? startSha[..7]}", secondStep ? 0.5 : 1.0),
-
578 default);
-
579
-
580 if (secondStep)
-
581 await repo.ResetToSha(startSha, progressReporter.CreateSection($"Hard reset to SHA {startSha[..7]}", 0.5), default);
+
538 fullTestMerge = new Models.TestMerge
+
539 {
+
540 Author = ex.Message,
+
541 BodyAtMerge = ex.Message,
+
542 TitleAtMerge = ex.Message,
+
543 Comment = newTestMerge.Comment,
+
544 Number = newTestMerge.Number,
+
545 Url = ex.Message,
+
546 };
+
547 }
+
548
+
549 // Ensure we're getting the full sha from git itself
+
550 fullTestMerge.TargetCommitSha = newTestMerge.TargetCommitSha;
+
551
+
552 await UpdateRevInfo(fullTestMerge);
+
553 }
+
554 }
+
555 }
+
556
+
557 var currentHead = repo.Head;
+
558 if (currentModel.PushTestMergeCommits!.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead)))
+
559 {
+
560 using (var syncReporter = NextProgressReporter("Synchronize"))
+
561 await repo.Synchronize(
+
562 syncReporter,
+
563 currentModel.AccessUser,
+
564 currentModel.AccessToken,
+
565 currentModel.CommitterName!,
+
566 currentModel.CommitterEmail!,
+
567 false,
+
568 false,
+
569 cancellationToken);
+
570
+
571 await UpdateRevInfo();
+
572 }
+
573 }
+
574 catch
+
575 {
+
576 numSteps = 2;
+
577
+
578 // Forget what we've done and abort
+
579 progressReporter.ReportProgress(0.0);
+
580
+
581 var secondStep = startReference != null && repo.Head != startSha;
582
-
583 throw;
-
584 }
-
585 }
-
586
-
595 public async ValueTask RepositoryRecloneJob(
-
596 IInstanceCore? instance,
-
597 IDatabaseContextFactory databaseContextFactory,
-
598 JobProgressReporter progressReporter,
-
599 CancellationToken cancellationToken)
-
600 {
-
601 ArgumentNullException.ThrowIfNull(instance);
-
602 ArgumentNullException.ThrowIfNull(databaseContextFactory);
-
603 ArgumentNullException.ThrowIfNull(progressReporter);
-
604
-
605 progressReporter.StageName = "Loading Old Repository";
-
606
-
607 Uri origin;
-
608 string? oldReference;
-
609 string oldSha;
-
610 ValueTask deleteTask;
-
611 using (var oldRepo = await instance.RepositoryManager.LoadRepository(cancellationToken))
-
612 {
-
613 if (oldRepo == null)
-
614 throw new JobException(ErrorCode.RepoMissing);
-
615
-
616 origin = oldRepo.Origin;
-
617 oldSha = oldRepo.Head;
-
618 oldReference = oldRepo.Reference;
-
619 if (oldReference == Repository.NoReference)
-
620 oldReference = null;
+
583 // DCTx2: Cancellation token is for job, operations should always run
+
584 using (var checkoutReporter = progressReporter.CreateSection($"Checkout {startReference ?? startSha[..7]}", secondStep ? 0.5 : 1.0))
+
585 await repo.CheckoutObject(
+
586 startReference ?? startSha,
+
587 currentModel.AccessUser,
+
588 currentModel.AccessToken,
+
589 true,
+
590 false,
+
591 checkoutReporter,
+
592 default);
+
593
+
594 if (secondStep)
+
595 using (var resetReporter = progressReporter.CreateSection($"Hard reset to SHA {startSha[..7]}", 0.5))
+
596 await repo.ResetToSha(startSha, resetReporter, default);
+
597
+
598 throw;
+
599 }
+
600 }
+
601
+
610 public async ValueTask RepositoryRecloneJob(
+
611 IInstanceCore? instance,
+
612 IDatabaseContextFactory databaseContextFactory,
+
613 JobProgressReporter progressReporter,
+
614 CancellationToken cancellationToken)
+
615 {
+
616 ArgumentNullException.ThrowIfNull(instance);
+
617 ArgumentNullException.ThrowIfNull(databaseContextFactory);
+
618 ArgumentNullException.ThrowIfNull(progressReporter);
+
619
+
620 progressReporter.StageName = "Loading Old Repository";
621
-
622 progressReporter.StageName = "Deleting Old Repository";
-
623 deleteTask = instance.RepositoryManager.DeleteRepository(cancellationToken);
-
624 }
-
625
-
626 await deleteTask;
-
627 progressReporter.ReportProgress(0.1);
-
628 IRepository newRepo;
-
629 try
-
630 {
-
631 newRepo = await instance.RepositoryManager.CloneRepository(
-
632 origin,
-
633 oldReference,
-
634 currentModel.AccessUser,
-
635 currentModel.AccessToken,
-
636 progressReporter.CreateSection("Cloning New Repository", 0.8),
-
637 true, // TODO: Make configurable maybe...
-
638 cancellationToken)
-
639 ?? throw new JobException("A race condition occurred while recloning the repository. Somehow, it was fully cloned instantly after being deleted!"); // I'll take lines of code that should never be hit for $10k
-
640 }
-
641 catch (Exception ex) when (ex is not JobException)
-
642 {
-
643 logger.LogWarning("Reclone failed, clearing credentials!");
+
622 Uri origin;
+
623 string? oldReference;
+
624 string oldSha;
+
625 ValueTask deleteTask;
+
626 using (var deleteReporter = progressReporter.CreateSection("Deleting Old Repository", 0.1))
+
627 {
+
628 using (var oldRepo = await instance.RepositoryManager.LoadRepository(cancellationToken))
+
629 {
+
630 if (oldRepo == null)
+
631 throw new JobException(ErrorCode.RepoMissing);
+
632
+
633 origin = oldRepo.Origin;
+
634 oldSha = oldRepo.Head;
+
635 oldReference = oldRepo.Reference;
+
636 if (oldReference == Repository.NoReference)
+
637 oldReference = null;
+
638
+
639 deleteTask = instance.RepositoryManager.DeleteRepository(cancellationToken);
+
640 }
+
641
+
642 await deleteTask;
+
643 }
644
-
645 // need to clear credentials here
-
646 await databaseContextFactory.UseContextTaskReturn(context =>
-
647 {
-
648 context.RepositorySettings.Attach(currentModel);
-
649 currentModel.AccessUser = null;
-
650 currentModel.AccessToken = null;
-
651 return context.Save(CancellationToken.None); // DCT: Must always run
-
652 });
-
653
-
654 throw;
-
655 }
-
656
-
657 using (newRepo)
-
658 await newRepo.CheckoutObject(
-
659 oldSha,
-
660 currentModel.AccessUser,
-
661 currentModel.AccessToken,
-
662 false,
-
663 oldReference != null,
-
664 progressReporter.CreateSection("Checking out previous Detached Commit", 0.1),
-
665 cancellationToken);
-
666 }
-
667 }
-
668}
+
645 IRepository newRepo;
+
646 try
+
647 {
+
648 using var cloneReporter = progressReporter.CreateSection("Cloning New Repository", 0.8);
+
649 newRepo = await instance.RepositoryManager.CloneRepository(
+
650 origin,
+
651 oldReference,
+
652 currentModel.AccessUser,
+
653 currentModel.AccessToken,
+
654 cloneReporter,
+
655 true, // TODO: Make configurable maybe...
+
656 cancellationToken)
+
657 ?? throw new JobException("A race condition occurred while recloning the repository. Somehow, it was fully cloned instantly after being deleted!"); // I'll take lines of code that should never be hit for $10k
+
658 }
+
659 catch (Exception ex) when (ex is not JobException)
+
660 {
+
661 logger.LogWarning("Reclone failed, clearing credentials!");
+
662
+
663 // need to clear credentials here
+
664 await databaseContextFactory.UseContextTaskReturn(context =>
+
665 {
+
666 context.RepositorySettings.Attach(currentModel);
+
667 currentModel.AccessUser = null;
+
668 currentModel.AccessToken = null;
+
669 return context.Save(CancellationToken.None); // DCT: Must always run
+
670 });
+
671
+
672 throw;
+
673 }
+
674
+
675 using (newRepo)
+
676 using (var checkoutReporter = progressReporter.CreateSection("Checking out previous Detached Commit", 0.1))
+
677 {
+
678 await newRepo.CheckoutObject(
+
679 oldSha,
+
680 currentModel.AccessUser,
+
681 currentModel.AccessToken,
+
682 false,
+
683 oldReference != null,
+
684 checkoutReporter,
+
685 cancellationToken);
+
686 }
+
687 }
+
688 }
+
689}
Exception
IQueryable
Tgstation.Server.Api.Models.EntityId.Id
virtual ? long Id
The ID of the entity.
Definition: EntityId.cs:13
@@ -717,16 +738,18 @@ $(function() {
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService
Service for performing the complex Job of updating the repository on user request.
Definition: RepositoryUpdateService.cs:24
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.RepositoryUpdateService
RepositoryUpdateService(RepositorySettings currentModel, User initiatingUser, ILogger< RepositoryUpdateService > logger, long instanceId)
Initializes a new instance of the RepositoryUpdateService class.
Definition: RepositoryUpdateService.cs:52
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.logger
readonly ILogger< RepositoryUpdateService > logger
The ILogger<TCategoryName> for the RepositoryUpdateService.
Definition: RepositoryUpdateService.cs:38
-
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.RepositoryRecloneJob
async ValueTask RepositoryRecloneJob(IInstanceCore? instance, IDatabaseContextFactory databaseContextFactory, JobProgressReporter progressReporter, CancellationToken cancellationToken)
The job entrypoint used by Controllers.RepositoryController to reclone a repository.
Definition: RepositoryUpdateService.cs:595
+
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.RepositoryRecloneJob
async ValueTask RepositoryRecloneJob(IInstanceCore? instance, IDatabaseContextFactory databaseContextFactory, JobProgressReporter progressReporter, CancellationToken cancellationToken)
The job entrypoint used by Controllers.RepositoryController to reclone a repository.
Definition: RepositoryUpdateService.cs:610
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.instanceId
readonly long instanceId
The EntityId.Id of the associated Instance.
Definition: RepositoryUpdateService.cs:43
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.currentModel
readonly RepositorySettings currentModel
The current RepositorySettings for the RepositoryUpdateService.
Definition: RepositoryUpdateService.cs:28
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.RepositoryUpdateJob
async ValueTask RepositoryUpdateJob(RepositoryUpdateRequest model, IInstanceCore? instance, IDatabaseContextFactory databaseContextFactory, JobProgressReporter progressReporter, CancellationToken cancellationToken)
The job entrypoint used by Controllers.RepositoryController to update the repository's current HEAD.
Definition: RepositoryUpdateService.cs:141
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.initiatingUser
readonly User initiatingUser
The User that initiated the repository update.
Definition: RepositoryUpdateService.cs:33
Tgstation.Server.Host.Components.Repository.RepositoryUpdateService.LoadRevisionInformation
static async ValueTask< bool > LoadRevisionInformation(IRepository repository, IDatabaseContext databaseContext, ILogger logger, Models.Instance instance, string? lastOriginCommitSha, Action< Models.RevisionInformation >? revInfoSink, CancellationToken cancellationToken)
Load the RevisionInformation for the current repository state into a given databaseContext .
Definition: RepositoryUpdateService.cs:75
+
Tgstation.Server.Host.Components.Repository.TestMergeResult
Represents the result of a repository test merge attempt.
Definition: TestMergeResult.cs:11
+
Tgstation.Server.Host.Components.Repository.TestMergeResult.Status
MergeStatus Status
The resulting MergeStatus.
Definition: TestMergeResult.cs:15
Tgstation.Server.Host.Jobs.JobException
Operation exceptions thrown from the context of a Models.Job.
Definition: JobException.cs:11
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:100
-
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:74
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:176
+
Tgstation.Server.Host.Jobs.JobProgressReporter.ReportProgress
void ReportProgress(double? progress)
Report progress.
Definition: JobProgressReporter.cs:137
Tgstation.Server.Host.Models.Instance
Represents an Api.Models.Instance in the database.
Definition: Instance.cs:11
Tgstation.Server.Host.Models.RepositorySettings
Definition: RepositorySettings.cs:9
Tgstation.Server.Host.Models.RevInfoTestMerge
Many to many relationship for Models.RevisionInformation and Models.TestMerge.
Definition: RevInfoTestMerge.cs:10
@@ -738,7 +761,7 @@ $(function() {
Tgstation.Server.Host.Components.Repository.IRepository
Represents an on-disk git repository.
Definition: IRepository.cs:14
Tgstation.Server.Host.Components.Repository.IRepository.TimestampCommit
Task< DateTimeOffset > TimestampCommit(string sha, CancellationToken cancellationToken)
Gets the DateTimeOffset a given sha was created on.
Tgstation.Server.Host.Components.Repository.IRepository.Head
string Head
The SHA of the IRepository HEAD.
Definition: IRepository.cs:23
-
Tgstation.Server.Host.Components.Repository.IRepository.CheckoutObject
ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
Checks out a given committish .
+
Tgstation.Server.Host.Components.Repository.IRepository.CheckoutObject
ValueTask CheckoutObject(string committish, string? username, string? password, bool updateSubmodules, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Checks out a given committish .
Tgstation.Server.Host.Database.IDatabaseCollection.Local
IEnumerable< TModel > Local
An IEnumerable<T> of TModel s prioritizing in the working set.
Definition: IDatabaseCollection.cs:15
Tgstation.Server.Host.Database.IDatabaseCollection.Add
void Add(TModel model)
Add a given model to the the working set.
Tgstation.Server.Host.Database.IDatabaseContextFactory
Factory for scoping usage of IDatabaseContexts. Meant for use by Components.
Definition: IDatabaseContextFactory.cs:10
diff --git a/_session_controller_8cs_source.html b/_session_controller_8cs_source.html index 4757c442b0..79245a32c5 100644 --- a/_session_controller_8cs_source.html +++ b/_session_controller_8cs_source.html @@ -174,7 +174,7 @@ $(function() {
118
122 public FifoSemaphore TopicSendSemaphore { get; }
123
-
125 public long MemoryUsage => process.MemoryUsage;
+
125 public long? MemoryUsage => process.MemoryUsage;
126
130 readonly Byond.TopicSender.ITopicClient byondTopicSender;
131
@@ -1176,7 +1176,6 @@ $(function() {
Tgstation.Server.Host.Components.Session.SessionController.eventConsumer
readonly IEventConsumer eventConsumer
The IEventConsumer for the SessionController.
Definition: SessionController.cs:170
Tgstation.Server.Host.Components.Session.SessionController.BridgeError
BridgeResponse BridgeError(string message)
Log and return a BridgeResponse for a given message .
Definition: SessionController.cs:776
Tgstation.Server.Host.Components.Session.SessionController.released
bool released
If process should be kept alive instead.
Definition: SessionController.cs:245
-
Tgstation.Server.Host.Components.Session.SessionController.MemoryUsage
long MemoryUsage
Gets the process' memory usage in bytes.
Definition: SessionController.cs:125
Tgstation.Server.Host.Components.Session.SessionController.chat
readonly IChatManager chat
The IChatManager for the SessionController.
Definition: SessionController.cs:155
Tgstation.Server.Host.Components.Session.SessionController.chatTrackingContext
readonly IChatTrackingContext chatTrackingContext
The IChatTrackingContext for the SessionController.
Definition: SessionController.cs:150
Tgstation.Server.Host.Components.Session.SessionController.Lifetime
Task< int?> Lifetime
The Task<TResult> resulting in the exit code of the process or null if the process was detached.
Definition: SessionController.cs:74
@@ -1192,6 +1191,7 @@ $(function() {
Tgstation.Server.Host.Components.Session.SessionController.GenerateQueryString
string GenerateQueryString(TopicParameters parameters, out string json)
Generates a Byond.TopicSender.ITopicClient query string for a given set of parameters .
Definition: SessionController.cs:917
Tgstation.Server.Host.Components.Session.SessionController.CheckDisposed
void CheckDisposed()
Throws an ObjectDisposedException if DisposeAsync has been called.
Tgstation.Server.Host.Components.Session.SessionController.bridgeRegistration
readonly? IBridgeRegistration bridgeRegistration
The IBridgeRegistration for the SessionController.
Definition: SessionController.cs:135
+
Tgstation.Server.Host.Components.Session.SessionController.MemoryUsage
long? MemoryUsage
Gets the process' memory usage in bytes.
Definition: SessionController.cs:125
Tgstation.Server.Host.Components.Session.SessionController.GetLaunchResult
async Task< LaunchResult > GetLaunchResult(IAssemblyInformationProvider assemblyInformationProvider, IAsyncDelayer asyncDelayer, uint? startupTimeout, bool reattached, bool apiValidate)
The Task<TResult> for LaunchResult.
Definition: SessionController.cs:528
Tgstation.Server.Host.Components.Session.SessionController.ReplaceDmbProvider
IAsyncDisposable ReplaceDmbProvider(IDmbProvider dmbProvider)
Replace the IDmbProvider in use with a given newProvider , disposing the old one. An IAsyncDisposable...
Definition: SessionController.cs:484
Tgstation.Server.Host.Components.Session.SessionController.OnStartup
Task OnStartup
A Task that completes when the server calls /world/TgsNew().
Definition: SessionController.cs:77
@@ -1246,7 +1246,7 @@ $(function() {
Tgstation.Server.Host.System.IProcessBase.SuspendProcess
void SuspendProcess()
Suspends the process.
Tgstation.Server.Host.System.IProcessBase.ResumeProcess
void ResumeProcess()
Resumes the process.
Tgstation.Server.Host.System.IProcessBase.AdjustPriority
void AdjustPriority(bool higher)
Set's the owned global::System.Diagnostics.Process.PriorityClass to a non-normal value.
-
Tgstation.Server.Host.System.IProcessBase.MemoryUsage
long MemoryUsage
Gets the process' memory usage in bytes.
Definition: IProcessBase.cs:19
+
Tgstation.Server.Host.System.IProcessBase.MemoryUsage
long? MemoryUsage
Gets the process' memory usage in bytes.
Definition: IProcessBase.cs:19
Tgstation.Server.Host.System.IProcessBase.CreateDump
ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
Create a dump file of the process.
Tgstation.Server.Host.System.IProcessBase.Lifetime
Task< int?> Lifetime
The Task<TResult> resulting in the exit code of the process or null if the process was detached.
Definition: IProcessBase.cs:14
Tgstation.Server.Host.System.IProcess
Abstraction over a global::System.Diagnostics.Process.
Definition: IProcess.cs:11
diff --git a/_tgstation_8_server_8_host_2_components_2_instance_8cs_source.html b/_tgstation_8_server_8_host_2_components_2_instance_8cs_source.html index 6bc5b5dd5b..68ae7d64da 100644 --- a/_tgstation_8_server_8_host_2_components_2_instance_8cs_source.html +++ b/_tgstation_8_server_8_host_2_components_2_instance_8cs_source.html @@ -625,7 +625,7 @@ $(function() {
Tgstation.Server.Host.Components.Deployment.DreamMaker.DeploymentProcess
async ValueTask DeploymentProcess(Models.Job job, IDatabaseContextFactory databaseContextFactory, JobProgressReporter progressReporter, CancellationToken cancellationToken)
Definition: DreamMaker.cs:191
Tgstation.Server.Host.Components.Engine.EngineManager
Definition: EngineManager.cs:23
Tgstation.Server.Host.Components.Engine.EngineManager.StopAsync
Task StopAsync(CancellationToken cancellationToken)
-
Tgstation.Server.Host.Components.Engine.EngineManager.StartAsync
async Task StartAsync(CancellationToken cancellationToken)
Definition: EngineManager.cs:298
+
Tgstation.Server.Host.Components.Engine.EngineManager.StartAsync
async Task StartAsync(CancellationToken cancellationToken)
Definition: EngineManager.cs:301
Tgstation.Server.Host.Components.Engine.EngineManager.Dispose
void Dispose()
Tgstation.Server.Host.Components.Instance
Definition: Instance.cs:33
Tgstation.Server.Host.Components.Instance.timerTask
Task? timerTask
The auto update Task.
Definition: Instance.cs:100
@@ -657,8 +657,8 @@ $(function() {
Tgstation.Server.Host.Components.Repository.RepositoryManager.Dispose
void Dispose()
Definition: RepositoryManager.cs:114
Tgstation.Server.Host.Components.Repository.RepositoryManager.LoadRepository
async ValueTask< IRepository?> LoadRepository(CancellationToken cancellationToken)
Attempt to load the IRepository from the default location. A ValueTask<TResult> resulting in the load...
Definition: RepositoryManager.cs:211
Tgstation.Server.Host.Jobs.JobException
Operation exceptions thrown from the context of a Models.Job.
Definition: JobException.cs:11
-
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:13
-
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:100
+
Tgstation.Server.Host.Jobs.JobProgressReporter
Progress reporter for a Job.
Definition: JobProgressReporter.cs:14
+
Tgstation.Server.Host.Jobs.JobProgressReporter.CreateSection
JobProgressReporter CreateSection(string? newStageName, double percentage)
Create a subsection of the JobProgressReporter with its optional own stage name.
Definition: JobProgressReporter.cs:176
Tgstation.Server.Host.Models.Instance
Represents an Api.Models.Instance in the database.
Definition: Instance.cs:11
Tgstation.Server.Host.Models.Job
Definition: Job.cs:16
Tgstation.Server.Host.Models.Job.Create
static Job Create(JobCode code, User? startedBy, Api.Models.Instance instance)
Creates a new job for registering in the Jobs.IJobService.
diff --git a/_watchdog_base_8cs_source.html b/_watchdog_base_8cs_source.html index 4140011a1c..1655e0a6f9 100644 --- a/_watchdog_base_8cs_source.html +++ b/_watchdog_base_8cs_source.html @@ -124,7 +124,7 @@ $(function() {
50 }
51 }
52
-
54 public long? MemoryUsage => GetActiveController()?.MemoryUsage;
+
54 public long? MemoryUsage => GetActiveController()?.MemoryUsage;
55
57 public abstract bool AlphaIsActive { get; }
58
@@ -1253,7 +1253,7 @@ $(function() {
Tgstation.Server.Host.IO.IIOManager
Interface for using filesystems.
Definition: IIOManager.cs:13
Tgstation.Server.Host.Jobs.IJobManager
Manages the runtime of Jobs.
Definition: IJobManager.cs:13
Tgstation.Server.Host.Jobs.IJobManager.RegisterOperation
ValueTask RegisterOperation(Job job, JobEntrypoint operation, CancellationToken cancellationToken)
Registers a given Job and begins running it.
-
Tgstation.Server.Host.System.IProcessBase.MemoryUsage
long MemoryUsage
Gets the process' memory usage in bytes.
Definition: IProcessBase.cs:19
+
Tgstation.Server.Host.System.IProcessBase.MemoryUsage
long? MemoryUsage
Gets the process' memory usage in bytes.
Definition: IProcessBase.cs:19
Tgstation.Server.Host.Utils.IAsyncDelayer
For waiting asynchronously.
Definition: IAsyncDelayer.cs:11
Tgstation.Server.Api.Models.Internal
Definition: ChatBotApiBase.cs:6
Tgstation.Server.Api.Models
Definition: ChatChannel.cs:6
diff --git a/_windows_open_dream_installer_8cs_source.html b/_windows_open_dream_installer_8cs_source.html index 28ad7ac442..9dea4c76de 100644 --- a/_windows_open_dream_installer_8cs_source.html +++ b/_windows_open_dream_installer_8cs_source.html @@ -196,7 +196,7 @@ $(function() {
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.IOManager
IIOManager IOManager
Gets the IIOManager for the EngineInstallerBase.
Definition: EngineInstallerBase.cs:24
Tgstation.Server.Host.Components.Engine.EngineInstallerBase.Logger
ILogger< EngineInstallerBase > Logger
Gets the ILogger for the EngineInstallerBase.
Definition: EngineInstallerBase.cs:29
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller
Implementation of IEngineInstaller for EngineType.OpenDream.
Definition: OpenDreamInstaller.cs:25
-
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.GetExecutablePaths
void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath)
Gets the paths to the server and client executables.
Definition: OpenDreamInstaller.cs:356
+
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.GetExecutablePaths
void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath)
Gets the paths to the server and client executables.
Definition: OpenDreamInstaller.cs:373
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.httpClientFactory
readonly IAbstractHttpClientFactory httpClientFactory
The IAbstractHttpClientFactory for the OpenDreamInstaller.
Definition: OpenDreamInstaller.cs:82
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.platformIdentifier
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the OpenDreamInstaller.
Definition: OpenDreamInstaller.cs:67
Tgstation.Server.Host.Components.Engine.OpenDreamInstaller.repositoryManager
readonly IRepositoryManager repositoryManager
The IRepositoryManager for the OpenDream repository.
Definition: OpenDreamInstaller.cs:72
diff --git a/changelog.yml b/changelog.yml index 3dcbe47c9b..5d432beb97 100644 --- a/changelog.yml +++ b/changelog.yml @@ -182,6 +182,11 @@ Components: - The version in use can now be anonymously reported for statistics. Author: Cyberboss PullRequest: 1859 + - Descriptions: + - Fixed several inconsistencies related to job progress reporting. + - Fixed request failures that could occur while querying game server memory as the process was crashing. + Author: Cyberboss + PullRequest: 1881 Unreleased: true - Version: 6.8.1 ComponentVersions: diff --git a/class_i_disposable.html b/class_i_disposable.html index bacec75e70..e94827d242 100644 --- a/class_i_disposable.html +++ b/class_i_disposable.html @@ -78,7 +78,7 @@ Inheritance diagram for IDisposable:
Inheritance graph
- + @@ -86,27 +86,28 @@ Inheritance diagram for IDisposable:
- + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -118,8 +119,8 @@ Inheritance diagram for IDisposable: - - + +
[legend]

The documentation for this class was generated from the following file: