From e26f84a9b75f250f951e0efa5c5c62860b3c8370 Mon Sep 17 00:00:00 2001 From: Roger Luo Date: Fri, 10 Jun 2022 00:10:33 +0000 Subject: [PATCH 1/3] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 1 - options/locale/locale_de-DE.ini | 1 - options/locale/locale_el-GR.ini | 1 - options/locale/locale_es-ES.ini | 1 - options/locale/locale_fa-IR.ini | 1 - options/locale/locale_fr-FR.ini | 1 - options/locale/locale_hu-HU.ini | 1 - options/locale/locale_id-ID.ini | 1 - options/locale/locale_it-IT.ini | 1 - options/locale/locale_ja-JP.ini | 1 - options/locale/locale_ko-KR.ini | 1 - options/locale/locale_lv-LV.ini | 1 - options/locale/locale_ml-IN.ini | 1 - options/locale/locale_nl-NL.ini | 1 - options/locale/locale_pl-PL.ini | 1 - options/locale/locale_pt-BR.ini | 1 - options/locale/locale_pt-PT.ini | 4 +++- options/locale/locale_ru-RU.ini | 1 - options/locale/locale_si-LK.ini | 1 - options/locale/locale_sv-SE.ini | 1 - options/locale/locale_tr-TR.ini | 1 - options/locale/locale_uk-UA.ini | 1 - options/locale/locale_zh-CN.ini | 1 - options/locale/locale_zh-TW.ini | 1 - 24 files changed, 3 insertions(+), 24 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index ab59766d6c..5dafbfdb16 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -694,7 +694,6 @@ generate_token_success=Váše nová poukázka byla vytvořena. Zkopírujte ji ny generate_token_name_duplicate=%s byl již použit jako název aplikace. Použijte prosím nový. delete_token=Smazat access_token_deletion=Odstranit přístupovou poukázku -access_token_deletion_desc=Smazání poukázky zruší přístup k vašemu účtu pro aplikace, které ji používají. Pokračovat? delete_token_success=Poukázka byla odstraněna. Aplikace, které ji používají již nemají přístup k vašemu účtu. manage_oauth2_applications=Spravovat OAuth2 aplikace diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index d15b2104b8..442168cf69 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -704,7 +704,6 @@ generate_token_success=Ein neuer Token wurde generiert. Kopiere diesen, da er ni generate_token_name_duplicate=%s wurde bereits als Anwendungsname verwendet. Bitte wähle einen neuen Namen. delete_token=Löschen access_token_deletion=Zugriffstoken löschen -access_token_deletion_desc=Wenn du ein Token löschst, haben die Anwendungen, die es nutzen keinen Zugriff mehr auf deinen Account. Fortfahren? delete_token_success=Der Zugriffstoken wurde gelöscht. Anwendungen die diesen Token genutzt haben, haben nun keinen Zugriff mehr auf deinen Account. manage_oauth2_applications=OAuth2 Anwendungen verwalten diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 7459576914..0a5cbbd3e1 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -716,7 +716,6 @@ generate_token_success=Το νέο διακριτικό σας έχει δημι generate_token_name_duplicate=Το %s έχει ήδη χρησιμοποιηθεί ως όνομα εφαρμογής. Παρακαλούμε χρησιμοποιήστε ένα νέο. delete_token=Διαγραφή access_token_deletion=Διαγραφή Διακριτικού Πρόσβασης -access_token_deletion_desc=Η διαγραφή ενός διακριτικού θα ανακαλέσει την πρόσβαση στο λογαριασμό σας για εφαρμογές που χρησιμοποιούν αυτό. Συνέχεια; delete_token_success=Το διακριτικό έχει διαγραφεί. Οι εφαρμογές που το χρησιμοποιούν δεν έχουν πλέον πρόσβαση στο λογαριασμό σας. manage_oauth2_applications=Διαχείριση Εφαρμογών Oauth2 diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index eba3a8c1f2..5c98da03b9 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -707,7 +707,6 @@ generate_token_success=Su nuevo token ha sido generado. Cópielo ahora, ya que n generate_token_name_duplicate=%s ya se ha utilizado como nombre de la aplicación. Por favor, utilice una nueva. delete_token=Eliminar access_token_deletion=Eliminar Token de Acceso -access_token_deletion_desc=Eliminando un token revocará el acceso a su cuenta para todas las aplicaciones que lo usen. ¿Continuar? delete_token_success=El token ha sido eliminado. Las aplicaciones que lo usen ya no tienen acceso a su cuenta. manage_oauth2_applications=Administrar aplicaciones OAuth2 diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index ef34c0e842..a465c00145 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -661,7 +661,6 @@ generate_token_success=اکنون token جدید ساخته شد. همینک آ generate_token_name_duplicate=%s قبلا بعنوان نام یک برنامه استفاده شده است. لطفا از یک نام دیگر استفاده کنید. delete_token=حذف access_token_deletion=حذف توکن -access_token_deletion_desc=حذف token باعث از کار افتادن تمامی برنامه‎هایی که در آنها به کار رفته می‎شود. آیا ادامه می‎دهید؟ delete_token_success=token مورد نظر حذف شد. برنامه هایی که از آن استفاده می‎کنند به زودی دسترسی به حساب کاربری شما را از دست می‎دهند. manage_oauth2_applications=مدیریت برنامه‎های OAuth2 diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 66de56c3e6..4ee872901c 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -628,7 +628,6 @@ generate_token_success=Votre nouveau jeton a été généré. Copiez-le maintena generate_token_name_duplicate=%s a déjà été utilisé comme nom d'application. Veuillez en utiliser un nouveau. delete_token=Supprimer access_token_deletion=Suppression de jetons d'accès -access_token_deletion_desc=Supprimer un jeton révoquera l'accès à votre compte pour toutes les applications l'utilisant. Continuer ? delete_token_success=Ce jeton a été supprimé. Les applications l'utilisant n'ont plus accès à votre compte. manage_oauth2_applications=Gérer les applications OAuth2 diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index a523e1e8cf..790f11faf5 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -514,7 +514,6 @@ generate_token_success=Új token létrehozva. Másold le most, mivel többször generate_token_name_duplicate=A %s nevet már használja egy alkalmazás. Válassz kérlek más nevet. delete_token=Törlés access_token_deletion=Hozzáférési Token Törlése -access_token_deletion_desc=Egy token törlésével visszavonja a hozzáférést a fiókjához az ezt használó alkalmazásoktól. Folytatja? delete_token_success=A token törölve lett. Az ezt használó alkalmazásoknak többé nincs hozzáférése a fiókodhoz. manage_oauth2_applications=OAuth2 alkalmazások kezelése diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 77df83eb38..8d49ce2ac1 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -505,7 +505,6 @@ generate_token=Hasilkan Token generate_token_success=Token baru Anda telah dibuat. Salin sekarang oleh karena tidak akan ditampilkan lagi. delete_token=Hapus access_token_deletion=Hapus Token Akses -access_token_deletion_desc=Menghapus token akan mencabut akses ke akun Anda bagi aplikasi yang menggunakannya. Lanjutkan? delete_token_success=Token telah dihapus. Aplikasi yang menggunakannya tidak lagi memiliki akses ke akun Anda. manage_oauth2_applications=Kelola Aplikasi OAuth2 diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index bda0e8e7b5..0335f10449 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -568,7 +568,6 @@ generate_token_success=Il nuovo token è stato generato. Copia ora in quanto non generate_token_name_duplicate=%s è già stato utilizzato come nome dell'applicazione. Si prega di usarne uno nuovo. delete_token=Elimina access_token_deletion=Elimina token di accesso -access_token_deletion_desc=Eliminare un token revocherà l'accesso al tuo account alle applicazioni che lo utilizzano. Continuare? delete_token_success=Il token è stato eliminato. Le applicazioni che lo utilizzavano non hanno più accesso al tuo account. manage_oauth2_applications=Gestisci applicazioni OAuth2 diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index de8f989b6e..3699ac37b3 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -716,7 +716,6 @@ generate_token_success=あなたの新しいトークンを生成しました。 generate_token_name_duplicate=アプリケーション名 %s は既に使われています。他の名前を使用してください。 delete_token=削除 access_token_deletion=アクセストークンの削除 -access_token_deletion_desc=トークンを削除すると、それを使用しているアプリケーションは、アカウントへのアクセスができなくなります。 続行しますか? delete_token_success=トークンを削除しました。 削除したトークンを使用しているアプリケーションは、今後あなたのアカウントにアクセスできません。 manage_oauth2_applications=OAuth2アプリケーションの管理 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index f5d32e7793..625c31a5c7 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -487,7 +487,6 @@ generate_token=토큰 생성 generate_token_success=새로운 토큰이 생성되었습니다. 이 토큰은 다시 보이지 않으니 지금 복사하십시오. delete_token=삭제 access_token_deletion=액세스 토큰 삭제 -access_token_deletion_desc=토큰을 삭제하면 해당 토큰을 이용하는 어플리케이션으로부터 귀하의 계정에 대한 접근권한이 사라지게 됩니다. 계속하시겠습니까? delete_token_success=토큰이 삭제되었습니다. 해당 토큰을 사용하는 어플리케이션은 더 이상 이 계정으로 접근할 수 없습니다. manage_oauth2_applications=OAuth2 애플리케이션 관리 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 41b55f66de..537c04d3d8 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -695,7 +695,6 @@ generate_token_success=Piekļuves talons tika veiksmīgi uzģenerēts! Nokopēji generate_token_name_duplicate=Jau eksistē lietotne ar nosaukumu %s. Izmantojiet citu nosaukumu. delete_token=Dzēst access_token_deletion=Dzēst piekļuves talonu -access_token_deletion_desc=Dzēšot piekļuves talonu tiks liegta piekļuve visām aplikācijām, kas to izmanto. Vai turpināt? delete_token_success=Piekļuves talons tika noņemts. Neaizmirstiet atjaunot informāciju lietojumprogrammās, kas izmantoja šo talonu. manage_oauth2_applications=Pārvaldīt OAuth2 lietotnes diff --git a/options/locale/locale_ml-IN.ini b/options/locale/locale_ml-IN.ini index 64638f5073..ece816f891 100644 --- a/options/locale/locale_ml-IN.ini +++ b/options/locale/locale_ml-IN.ini @@ -475,7 +475,6 @@ generate_token=ടോക്കൺ സൃഷ്‌ടിക്കുക generate_token_success=നിങ്ങളുടെ പുതിയ ടോക്കൺ ജനറേറ്റുചെയ്‌തു. ഇത് വീണ്ടും കാണിക്കാത്തതിനാൽ ഇപ്പോൾ തന്നെ പകർത്തുക. delete_token=നീക്കം ചെയ്യുക access_token_deletion=ആക്‌സസ്സ് ടോക്കണ്‍ നീക്കം ചെയ്യുക -access_token_deletion_desc=ഒരു ടോക്കൺ ഇല്ലാതാക്കുന്നത് നിങ്ങളുടെ അക്കൗണ്ട് ഉപയോഗിക്കുന്ന അപ്ലിക്കേഷനുകൾക്കുള്ള പ്രവേശനം അസാധുവാക്കും. തുടരട്ടേ? delete_token_success=ടോക്കൺ ഇല്ലാതാക്കി. ഇനി ഇത് ഉപയോഗിക്കുന്ന അപ്ലിക്കേഷനുകൾക്ക് നിങ്ങളുടെ അക്കൌണ്ടിലേക്ക് പ്രവേശനം ഉണ്ടാകില്ല. manage_oauth2_applications=OAuth2 അപ്ലിക്കേഷനുകൾ നിയന്ത്രിക്കുക diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 516d31bee1..efdd4e632b 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -590,7 +590,6 @@ generate_token_success=Je nieuwe token is gegenereerd. Kopieer hem nu, want hij generate_token_name_duplicate=%s is al gebruikt als een applicatienaam. Gebruik een nieuwe. delete_token=Verwijderen access_token_deletion=Verwijder toegangstoken -access_token_deletion_desc=Als je een token verwijdert, heeft de applicatie die hem gebruikt geen toegang meer tot je account. Doorgaan? delete_token_success=De token is verwijderd. Applicaties die hem gebruiken, verliezen toegang tot je account. manage_oauth2_applications=Beheer OAuth2-applicaties diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 0c1ca297cb..db96b31126 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -675,7 +675,6 @@ generate_token_success=Twój nowy token został wygenerowany. Skopiuj go teraz, generate_token_name_duplicate=%s istnieje już jako nazwa aplikacji. Użyj nowej. delete_token=Usuń access_token_deletion=Usuń token dostępu -access_token_deletion_desc=Usunięcie tokenu unieważni dostęp do Twojego konta aplikacjom, które z niego korzystały. Kontynuować? delete_token_success=Token został usunięty. Aplikacje używające go nie będą miały już dostępu do Twojego konta. manage_oauth2_applications=Zarządzaj aplikacjami OAuth2 diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 20a4478b75..7094e07347 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -716,7 +716,6 @@ generate_token_success=Seu novo token foi gerado. Copie-o agora, pois ele não s generate_token_name_duplicate=%s já foi usado como um nome de aplicativo. Por favor, use outro. delete_token=Excluir access_token_deletion=Excluir token de acesso -access_token_deletion_desc=A exclusão de um token revoga o acesso à sua conta para aplicativos que o usam. Continuar? delete_token_success=O token foi excluído. Os aplicativos que o utilizam já não têm acesso à sua conta. manage_oauth2_applications=Gerenciar aplicativos OAuth2 diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 301b596f5b..e675de4bae 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -716,7 +716,9 @@ generate_token_success=O seu novo código foi gerado. Copie-o agora porque não generate_token_name_duplicate=%s já foi usado como nome de uma aplicação. Tente outro. delete_token=Eliminar access_token_deletion=Eliminar código de acesso -access_token_deletion_desc=Eliminar um código revoga o acesso à sua conta nas aplicações que o usem. Quer continuar? +access_token_deletion_cancel_action=Cancelar +access_token_deletion_confirm_action=Eliminar +access_token_deletion_desc=Eliminar um código revoga o acesso à sua conta nas aplicações que o usem. Esta operação não poderá ser revertida. Quer continuar? delete_token_success=O código foi eliminado. Aplicações que o usavam deixaram de ter acesso à sua conta. manage_oauth2_applications=Gerir aplicações OAuth2 diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 62399104dd..2d99b043f9 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -710,7 +710,6 @@ generate_token_success=Новый токен создан. Скопируйте generate_token_name_duplicate=%s уже используется в качестве имени приложения. Пожалуйста, используйте другое имя. delete_token=Удалить access_token_deletion=Удалить токен доступа -access_token_deletion_desc=Удаление токена отменит доступ к вашей учетной записи для приложений, использующих его. Продолжить? delete_token_success=Токен удалён. Приложения, использующие его, больше не имеют доступа к вашему аккаунту. manage_oauth2_applications=Управление приложениями OAuth2 diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 70463997d3..460d61c7c4 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -643,7 +643,6 @@ generate_token_success=ඔබේ නව ටෝකනය ජනනය කර ඇ generate_token_name_duplicate=%s දැනටමත් යෙදුම් නාමයක් ලෙස භාවිතා කර ඇත. කරුණාකර අලුත් එකක් භාවිතා කරන්න. delete_token=මකන්න access_token_deletion=ප්රවේශ ටෝකනය මකන්න -access_token_deletion_desc=ටෝකනයක් මකා දැමීමෙන් එය භාවිතා කරන යෙදුම් සඳහා ඔබගේ ගිණුමට ප්රවේශය අවලංගු වේ. දිගටම? delete_token_success=ටෝකනය මකා දමා ඇත. එය භාවිතා කරන යෙදුම් තවදුරටත් ඔබගේ ගිණුමට ප්රවේශය නොමැත. manage_oauth2_applications=OUTU2 යෙදුම් කළමනාකරණය කරන්න diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 831607e80f..1afca6b778 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -547,7 +547,6 @@ generate_token_success=Din nya token har genererats. Kopiera nu då den inte kom generate_token_name_duplicate=%s finns redan som programnamn. Välj ett annat. delete_token=Radera access_token_deletion=Ta bort åtkomst token -access_token_deletion_desc=Borttagning utav en token kommer återkalla åtkomst till ditt konto för de applikationer som använder den. Vill du fortsätta? delete_token_success=Token har tagits bort. Applikationer som använder den kommer inte längre ha åtkomst till ditt konto. manage_oauth2_applications=Hantera OAuth2-applikationer diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 7950b3b63f..6cabad7a69 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -649,7 +649,6 @@ generate_token_success=Yeni bir jeton oluşturuldu. Tekrar gösterilmeyeceği i generate_token_name_duplicate=%s zaten bir uygulama adı olarak kullanılmış. Lütfen yeni bir tane kullanın. delete_token=Sil access_token_deletion=Erişim Jetonunu Sil -access_token_deletion_desc=Bir jetonu silmek, onu kullanan uygulamalar için hesabınıza erişimi iptal eder. Devam edilsin mi? delete_token_success=Jeton silindi. Onu kullanan uygulamalar artık hesabınıza erişemez. manage_oauth2_applications=OAuth2 Uygulamalarını Yönet diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index e7b21a02bf..791a3bc105 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -669,7 +669,6 @@ generate_token_success=Ваш новий токен був створений. generate_token_name_duplicate=Назва програми %s вже використовується. Будь ласка, використайте нову. delete_token=Видалити access_token_deletion=Видалити токен доступу -access_token_deletion_desc=Видалення токена скасовує доступ до вашого облікового запису для програм, що використовують його. Продовжити? delete_token_success=Токен був знищений. Програми, що використовують його, більше не мають доступу до вашого облікового запису. manage_oauth2_applications=Керування програмами OAuth2 diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 65eb3b2c56..0f28fa8f34 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -717,7 +717,6 @@ generate_token_success=新令牌生成成功。请拷贝因为令牌将只会显 generate_token_name_duplicate=%s 已被用作应用程序名称。请使用一个新的名称。 delete_token=删除令牌 access_token_deletion=删除 Access Token -access_token_deletion_desc=删除 Access Token 将会阻止其他应用程序通过它访问你账号。是否继续? delete_token_success=令牌已经被删除。使用该令牌的应用将不再能够访问你的账号。 manage_oauth2_applications=管理 OAuth2 应用程序 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index f51ea14712..ef478990f5 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -715,7 +715,6 @@ generate_token_success=已經產生新的 Token。請立刻複製它,因為他 generate_token_name_duplicate=應用程式名稱 %s 已被使用,請換一個試試。 delete_token=刪除 access_token_deletion=刪除 Access Token -access_token_deletion_desc=刪除 Token 後,使用此 Token 的應用程式將無法再存取您的帳戶。是否繼續? delete_token_success=已刪除 Token。使用此 Token 的應用程式無法再存取您的帳戶。 manage_oauth2_applications=管理 OAuth2 應用程式 From a0051634b982608d94399033a8b76e7e3b1537ac Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 10 Jun 2022 09:57:49 +0800 Subject: [PATCH 2/3] Refactor git module, make Gitea use internal git config (#19732) * Refactor git module, make Gitea use internal git config, add safe.directory config * introduce git.InitSimple and git.InitWithConfigSync, make serv cmd use gitconfig * use HOME instead of GIT_CONFIG_GLOBAL, because git always needs a correct HOME * fix cmd env in cmd/serv.go * fine tune error message * Fix a incorrect test case * fix configAddNonExist * fix configAddNonExist logic, add `--fixed-value` flag, add tests * add configSetNonExist function in case it's needed. * use configSetNonExist for `user.name` and `user.email` * add some comments * Update cmd/serv.go Co-authored-by: zeripath * Update cmd/serv.go Co-authored-by: zeripath * Update modules/git/git.go Co-authored-by: zeripath * Update modules/setting/setting.go Co-authored-by: zeripath * Update modules/git/repo_attribute.go Co-authored-by: zeripath * fix spaces in messages * use `configSet("core.protectNTFS", ...)` instead of `globalCommandArgs` * remove GIT_CONFIG_NOSYSTEM, continue to use system's git config * Update cmd/serv.go Co-authored-by: zeripath * fix merge * remove code for safe.directory * separate git.CommonEnvs to CommonGitCmdEnvs and CommonCmdServEnvs * avoid Golang's data race error Co-authored-by: zeripath Co-authored-by: Lunny Xiao --- cmd/serv.go | 60 +++-- integrations/integration_test.go | 3 +- integrations/migration-test/migration_test.go | 1 + models/migrations/migrations_test.go | 5 +- models/unittest/testdb.go | 5 + modules/git/command.go | 40 ++- modules/git/commit.go | 5 - modules/git/git.go | 235 +++++++++++------- modules/git/git_test.go | 67 ++++- modules/git/lfs.go | 6 - modules/git/remote.go | 4 - modules/git/repo_attribute.go | 7 +- modules/git/repo_tree.go | 8 +- modules/indexer/stats/indexer_test.go | 2 +- modules/repository/init.go | 5 - modules/util/path.go | 1 + routers/init.go | 4 +- routers/web/admin/admin.go | 5 +- routers/web/repo/lfs.go | 5 +- services/pull/merge.go | 6 - services/repository/files/temp_repo.go | 5 - 21 files changed, 286 insertions(+), 193 deletions(-) diff --git a/cmd/serv.go b/cmd/serv.go index 6ba3e9de01..6e067a48a5 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -6,6 +6,7 @@ package cmd import ( + "context" "fmt" "net/http" "net/url" @@ -65,6 +66,21 @@ func setup(logPath string, debug bool) { if debug { setting.RunMode = "dev" } + + // Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when + // `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection. + if _, err := os.Stat(setting.RepoRootPath); err != nil { + if os.IsNotExist(err) { + _ = fail("Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath) + } else { + _ = fail("Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err) + } + return + } + + if err := git.InitSimple(context.Background()); err != nil { + _ = fail("Failed to init git", "Failed to init git, err: %v", err) + } } var ( @@ -80,12 +96,12 @@ var ( func fail(userMessage, logMessage string, args ...interface{}) error { // There appears to be a chance to cause a zombie process and failure to read the Exit status // if nothing is outputted on stdout. - fmt.Fprintln(os.Stdout, "") - fmt.Fprintln(os.Stderr, "Gitea:", userMessage) + _, _ = fmt.Fprintln(os.Stdout, "") + _, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage) if len(logMessage) > 0 { if !setting.IsProd { - fmt.Fprintf(os.Stderr, logMessage+"\n", args...) + _, _ = fmt.Fprintf(os.Stderr, logMessage+"\n", args...) } } ctx, cancel := installSignals() @@ -237,17 +253,6 @@ func runServ(c *cli.Context) error { } return fail("Internal Server Error", "%s", err.Error()) } - os.Setenv(repo_module.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki)) - os.Setenv(repo_module.EnvRepoName, results.RepoName) - os.Setenv(repo_module.EnvRepoUsername, results.OwnerName) - os.Setenv(repo_module.EnvPusherName, results.UserName) - os.Setenv(repo_module.EnvPusherEmail, results.UserEmail) - os.Setenv(repo_module.EnvPusherID, strconv.FormatInt(results.UserID, 10)) - os.Setenv(repo_module.EnvRepoID, strconv.FormatInt(results.RepoID, 10)) - os.Setenv(repo_module.EnvPRID, fmt.Sprintf("%d", 0)) - os.Setenv(repo_module.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID)) - os.Setenv(repo_module.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) - os.Setenv(repo_module.EnvAppURL, setting.AppURL) // LFS token authentication if verb == lfsAuthenticateVerb { @@ -298,20 +303,29 @@ func runServ(c *cli.Context) error { gitcmd = exec.CommandContext(ctx, verb, repoPath) } - // Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when - // `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection. - if _, err := os.Stat(setting.RepoRootPath); err != nil { - if os.IsNotExist(err) { - return fail("Incorrect configuration.", - "Directory `[repository]` `ROOT` %s was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.", setting.RepoRootPath) - } - } - process.SetSysProcAttribute(gitcmd) gitcmd.Dir = setting.RepoRootPath gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin gitcmd.Stderr = os.Stderr + gitcmd.Env = append(gitcmd.Env, os.Environ()...) + gitcmd.Env = append(gitcmd.Env, + repo_module.EnvRepoIsWiki+"="+strconv.FormatBool(results.IsWiki), + repo_module.EnvRepoName+"="+results.RepoName, + repo_module.EnvRepoUsername+"="+results.OwnerName, + repo_module.EnvPusherName+"="+results.UserName, + repo_module.EnvPusherEmail+"="+results.UserEmail, + repo_module.EnvPusherID+"="+strconv.FormatInt(results.UserID, 10), + repo_module.EnvRepoID+"="+strconv.FormatInt(results.RepoID, 10), + repo_module.EnvPRID+"="+fmt.Sprintf("%d", 0), + repo_module.EnvDeployKeyID+"="+fmt.Sprintf("%d", results.DeployKeyID), + repo_module.EnvKeyID+"="+fmt.Sprintf("%d", results.KeyID), + repo_module.EnvAppURL+"="+setting.AppURL, + ) + // to avoid breaking, here only use the minimal environment variables for the "gitea serv" command. + // it could be re-considered whether to use the same git.CommonGitCmdEnvs() as "git" command later. + gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...) + if err = gitcmd.Run(); err != nil { return fail("Internal error", "Failed to execute git command: %v", err) } diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 687591d5fa..0a41546554 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -274,8 +274,8 @@ func prepareTestEnv(t testing.TB, skip ...int) func() { deferFn := PrintCurrentTest(t, ourSkip) assert.NoError(t, unittest.LoadFixtures()) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) - assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) + assert.NoError(t, git.InitWithConfigSync(context.Background())) ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { assert.NoError(t, err, "unable to read the new repo root: %v\n", err) @@ -576,6 +576,7 @@ func resetFixtures(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) + assert.NoError(t, git.InitWithConfigSync(context.Background())) ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { assert.NoError(t, err, "unable to read the new repo root: %v\n", err) diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index 6a431504a0..45e31ff9ac 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -62,6 +62,7 @@ func initMigrationTest(t *testing.T) func() { assert.True(t, len(setting.RepoRootPath) != 0) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) + assert.NoError(t, git.InitWithConfigSync(context.Background())) ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { assert.NoError(t, err, "unable to read the new repo root: %v\n", err) diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go index a1fd49a8b9..2c4d21d974 100644 --- a/models/migrations/migrations_test.go +++ b/models/migrations/migrations_test.go @@ -202,9 +202,8 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En ourSkip += skip deferFn := PrintCurrentTest(t, ourSkip) assert.NoError(t, os.RemoveAll(setting.RepoRootPath)) - - assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), - setting.RepoRootPath)) + assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) + assert.NoError(t, git.InitWithConfigSync(context.Background())) ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { assert.NoError(t, err, "unable to read the new repo root: %v\n", err) diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index 117614a7a4..2a366836fe 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" @@ -116,6 +117,9 @@ func MainTest(m *testing.M, testOpts *TestOptions) { if err = CopyDir(filepath.Join(testOpts.GiteaRootPath, "integrations", "gitea-repositories-meta"), setting.RepoRootPath); err != nil { fatalTestError("util.CopyDir: %v\n", err) } + if err = git.InitWithConfigSync(context.Background()); err != nil { + fatalTestError("git.Init: %v\n", err) + } ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { @@ -198,6 +202,7 @@ func PrepareTestEnv(t testing.TB) { assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta") assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath)) + assert.NoError(t, git.InitWithConfigSync(context.Background())) ownerDirs, err := os.ReadDir(setting.RepoRootPath) assert.NoError(t, err) diff --git a/modules/git/command.go b/modules/git/command.go index f6344dbfd1..d71497f1d7 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -8,6 +8,7 @@ package git import ( "bytes" "context" + "errors" "fmt" "io" "os" @@ -104,6 +105,25 @@ type RunOpts struct { PipelineFunc func(context.Context, context.CancelFunc) error } +// CommonGitCmdEnvs returns the common environment variables for a "git" command. +func CommonGitCmdEnvs() []string { + // at the moment, do not set "GIT_CONFIG_NOSYSTEM", users may have put some configs like "receive.certNonceSeed" in it + return []string{ + fmt.Sprintf("LC_ALL=%s", DefaultLocale), + "GIT_TERMINAL_PROMPT=0", // avoid prompting for credentials interactively, supported since git v2.3 + "GIT_NO_REPLACE_OBJECTS=1", // ignore replace references (https://git-scm.com/docs/git-replace) + "HOME=" + HomeDir(), // make Gitea use internal git config only, to prevent conflicts with user's git config + } +} + +// CommonCmdServEnvs is like CommonGitCmdEnvs but it only returns minimal required environment variables for the "gitea serv" command +func CommonCmdServEnvs() []string { + return []string{ + "GIT_NO_REPLACE_OBJECTS=1", // ignore replace references (https://git-scm.com/docs/git-replace) + "HOME=" + HomeDir(), // make Gitea use internal git config only, to prevent conflicts with user's git config + } +} + // Run runs the command with the RunOpts func (c *Command) Run(opts *RunOpts) error { if opts == nil { @@ -148,16 +168,8 @@ func (c *Command) Run(opts *RunOpts) error { cmd.Env = opts.Env } - cmd.Env = append( - cmd.Env, - fmt.Sprintf("LC_ALL=%s", DefaultLocale), - // avoid prompting for credentials interactively, supported since git v2.3 - "GIT_TERMINAL_PROMPT=0", - // ignore replace references (https://git-scm.com/docs/git-replace) - "GIT_NO_REPLACE_OBJECTS=1", - ) - process.SetSysProcAttribute(cmd) + cmd.Env = append(cmd.Env, CommonGitCmdEnvs()...) cmd.Dir = opts.Dir cmd.Stdout = opts.Stdout cmd.Stderr = opts.Stderr @@ -184,7 +196,9 @@ func (c *Command) Run(opts *RunOpts) error { type RunStdError interface { error + Unwrap() error Stderr() string + IsExitCode(code int) bool } type runStdError struct { @@ -209,6 +223,14 @@ func (r *runStdError) Stderr() string { return r.stderr } +func (r *runStdError) IsExitCode(code int) bool { + var exitError *exec.ExitError + if errors.As(r.err, &exitError) { + return exitError.ExitCode() == code + } + return false +} + func bytesToString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go) } diff --git a/modules/git/commit.go b/modules/git/commit.go index 8c194ef502..99fbbd0cfc 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -398,11 +398,6 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) { // GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only') func (c *Commit) GetBranchName() (string, error) { - err := LoadGitVersion() - if err != nil { - return "", fmt.Errorf("Git version missing: %v", err) - } - args := []string{ "name-rev", } diff --git a/modules/git/git.go b/modules/git/git.go index 8fad070330..5817bd2c7f 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -10,11 +10,13 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "runtime" "strings" + "sync" "time" - "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "github.com/hashicorp/go-version" @@ -32,38 +34,33 @@ var ( GitExecutable = "git" // DefaultContext is the default context to run git commands in - // will be overwritten by Init with HammerContext + // will be overwritten by InitWithConfigSync with HammerContext DefaultContext = context.Background() - gitVersion *version.Version - // SupportProcReceive version >= 2.29.0 SupportProcReceive bool + + // initMutex is used to avoid Golang's data race error. see the comments below. + initMutex sync.Mutex + + gitVersion *version.Version ) -// LocalVersion returns current Git version from shell. -func LocalVersion() (*version.Version, error) { - if err := LoadGitVersion(); err != nil { - return nil, err - } - return gitVersion, nil -} - -// LoadGitVersion returns current Git version from shell. -func LoadGitVersion() error { +// loadGitVersion returns current Git version from shell. Internal usage only. +func loadGitVersion() (*version.Version, error) { // doesn't need RWMutex because its exec by Init() if gitVersion != nil { - return nil + return gitVersion, nil } - stdout, _, runErr := NewCommand(context.Background(), "version").RunStdString(nil) + stdout, _, runErr := NewCommand(DefaultContext, "version").RunStdString(nil) if runErr != nil { - return runErr + return nil, runErr } fields := strings.Fields(stdout) if len(fields) < 3 { - return fmt.Errorf("not enough output: %s", stdout) + return nil, fmt.Errorf("invalid git version output: %s", stdout) } var versionString string @@ -78,7 +75,7 @@ func LoadGitVersion() error { var err error gitVersion, err = version.NewVersion(versionString) - return err + return gitVersion, err } // SetExecutablePath changes the path of git executable and checks the file permission and version. @@ -93,7 +90,7 @@ func SetExecutablePath(path string) error { } GitExecutable = absPath - err = LoadGitVersion() + _, err = loadGitVersion() if err != nil { return fmt.Errorf("unable to load git version: %w", err) } @@ -120,7 +117,10 @@ func SetExecutablePath(path string) error { // VersionInfo returns git version information func VersionInfo() string { - format := "Git Version: %s" + if gitVersion == nil { + return "(git not found)" + } + format := "%s" args := []interface{}{gitVersion.Original()} // Since git wire protocol has been released from git v2.18 if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { @@ -131,8 +131,33 @@ func VersionInfo() string { return fmt.Sprintf(format, args...) } -// Init initializes git module -func Init(ctx context.Context) error { +// InitSimple initializes git module with a very simple step, no config changes, no global command arguments. +// This method doesn't change anything to filesystem +func InitSimple(ctx context.Context) error { + initMutex.Lock() + defer initMutex.Unlock() + + return initSimpleInternal(ctx) +} + +// HomeDir is the home dir for git to store the global config file used by Gitea internally +func HomeDir() string { + if setting.RepoRootPath == "" { + // TODO: now, some unit test code call the git module directly without initialization, which is incorrect. + // at the moment, we just use a temp HomeDir to prevent from conflicting with user's git config + // in the future, the git module should be initialized first before use. + tmpHomeDir := filepath.Join(os.TempDir(), "gitea-temp-home") + log.Error("Git's HomeDir is empty (RepoRootPath is empty), the git module is not initialized correctly, using a temp HomeDir (%s) temporarily", tmpHomeDir) + return tmpHomeDir + } + return setting.RepoRootPath +} + +func initSimpleInternal(ctx context.Context) error { + // at the moment, when running integration tests, the git.InitXxx would be called twice. + // one is called by the GlobalInitInstalled, one is called by TestMain. + // so the init functions should be protected by a mutex to avoid Golang's data race error. + DefaultContext = ctx if setting.Git.Timeout.Default > 0 { @@ -146,6 +171,23 @@ func Init(ctx context.Context) error { // force cleanup args globalCommandArgs = []string{} + return nil +} + +// InitWithConfigSync initializes git module. This method may create directories or write files into filesystem +func InitWithConfigSync(ctx context.Context) error { + initMutex.Lock() + defer initMutex.Unlock() + + err := initSimpleInternal(ctx) + if err != nil { + return err + } + + if err = os.MkdirAll(setting.RepoRootPath, os.ModePerm); err != nil { + return fmt.Errorf("unable to create directory %s, err: %w", setting.RepoRootPath, err) + } + if CheckGitVersionAtLeast("2.9") == nil { // Explicitly disable credential helper, otherwise Git credentials might leak globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") @@ -161,68 +203,71 @@ func Init(ctx context.Context) error { globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true") } - // Save current git version on init to gitVersion otherwise it would require an RWMutex - if err := LoadGitVersion(); err != nil { - return err - } - - // Git requires setting user.name and user.email in order to commit changes - if they're not set just add some defaults - for configKey, defaultValue := range map[string]string{"user.name": "Gitea", "user.email": "gitea@fake.local"} { - if err := checkAndSetConfig(configKey, defaultValue, false); err != nil { + // Git requires setting user.name and user.email in order to commit changes - old comment: "if they're not set just add some defaults" + // TODO: need to confirm whether users really need to change these values manually. It seems that these values are dummy only and not really used. + // If these values are not really used, then they can be set (overwritten) directly without considering about existence. + for configKey, defaultValue := range map[string]string{ + "user.name": "Gitea", + "user.email": "gitea@fake.local", + } { + if err := configSetNonExist(configKey, defaultValue); err != nil { return err } } // Set git some configurations - these must be set to these values for gitea to work correctly - if err := checkAndSetConfig("core.quotePath", "false", true); err != nil { + if err := configSet("core.quotePath", "false"); err != nil { return err } if CheckGitVersionAtLeast("2.10") == nil { - if err := checkAndSetConfig("receive.advertisePushOptions", "true", true); err != nil { + if err := configSet("receive.advertisePushOptions", "true"); err != nil { return err } } if CheckGitVersionAtLeast("2.18") == nil { - if err := checkAndSetConfig("core.commitGraph", "true", true); err != nil { + if err := configSet("core.commitGraph", "true"); err != nil { return err } - if err := checkAndSetConfig("gc.writeCommitGraph", "true", true); err != nil { + if err := configSet("gc.writeCommitGraph", "true"); err != nil { return err } } if CheckGitVersionAtLeast("2.29") == nil { // set support for AGit flow - if err := checkAndAddConfig("receive.procReceiveRefs", "refs/for"); err != nil { + if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { return err } SupportProcReceive = true } else { - if err := checkAndRemoveConfig("receive.procReceiveRefs", "refs/for"); err != nil { + if err := configUnsetAll("receive.procReceiveRefs", "refs/for"); err != nil { return err } SupportProcReceive = false } if runtime.GOOS == "windows" { - if err := checkAndSetConfig("core.longpaths", "true", true); err != nil { + if err := configSet("core.longpaths", "true"); err != nil { + return err + } + if setting.Git.DisableCoreProtectNTFS { + err = configSet("core.protectNTFS", "false") + } else { + err = configUnsetAll("core.protectNTFS", "false") + } + if err != nil { return err } } - if setting.Git.DisableCoreProtectNTFS { - if err := checkAndSetConfig("core.protectntfs", "false", true); err != nil { - return err - } - globalCommandArgs = append(globalCommandArgs, "-c", "core.protectntfs=false") - } + return nil } // CheckGitVersionAtLeast check git version is at least the constraint version func CheckGitVersionAtLeast(atLeast string) error { - if err := LoadGitVersion(); err != nil { + if _, err := loadGitVersion(); err != nil { return err } atLeastVersion, err := version.NewVersion(atLeast) @@ -235,75 +280,75 @@ func CheckGitVersionAtLeast(atLeast string) error { return nil } -func checkAndSetConfig(key, defaultValue string, forceToDefault bool) error { - stdout, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key) - if err != nil { - perr, ok := err.(*process.Error) - if !ok { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - eerr, ok := perr.Err.(*exec.ExitError) - if !ok || eerr.ExitCode() != 1 { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } +func configSet(key, value string) error { + stdout, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil) + if err != nil && !err.IsExitCode(1) { + return fmt.Errorf("failed to get git config %s, err: %w", key, err) } currValue := strings.TrimSpace(stdout) - - if currValue == defaultValue || (!forceToDefault && len(currValue) > 0) { + if currValue == value { return nil } - if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", key, defaultValue); err != nil { - return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr) + _, _, err = NewCommand(DefaultContext, "config", "--global", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to set git global config %s, err: %w", key, err) } return nil } -func checkAndAddConfig(key, value string) error { - _, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key, value) - if err != nil { - perr, ok := err.(*process.Error) - if !ok { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - eerr, ok := perr.Err.(*exec.ExitError) - if !ok || eerr.ExitCode() != 1 { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - if eerr.ExitCode() == 1 { - if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", "--add", key, value); err != nil { - return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr) - } - return nil +func configSetNonExist(key, value string) error { + _, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil) + if err == nil { + // already exist + return nil + } + if err.IsExitCode(1) { + // not exist, set new config + _, _, err = NewCommand(DefaultContext, "config", "--global", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to set git global config %s, err: %w", key, err) } + return nil } - return nil + return fmt.Errorf("failed to get git config %s, err: %w", key, err) } -func checkAndRemoveConfig(key, value string) error { - _, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key, value) - if err != nil { - perr, ok := err.(*process.Error) - if !ok { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - eerr, ok := perr.Err.(*exec.ExitError) - if !ok || eerr.ExitCode() != 1 { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - if eerr.ExitCode() == 1 { - return nil - } +func configAddNonExist(key, value string) error { + _, _, err := NewCommand(DefaultContext, "config", "--fixed-value", "--get", key, value).RunStdString(nil) + if err == nil { + // already exist + return nil } - - if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", "--unset-all", key, value); err != nil { - return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr) + if err.IsExitCode(1) { + // not exist, add new config + _, _, err = NewCommand(DefaultContext, "config", "--global", "--add", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to add git global config %s, err: %w", key, err) + } + return nil } + return fmt.Errorf("failed to get git config %s, err: %w", key, err) +} - return nil +func configUnsetAll(key, value string) error { + _, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil) + if err == nil { + // exist, need to remove + _, _, err = NewCommand(DefaultContext, "config", "--global", "--fixed-value", "--unset-all", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to unset git global config %s, err: %w", key, err) + } + return nil + } + if err.IsExitCode(1) { + // not exist + return nil + } + return fmt.Errorf("failed to get git config %s, err: %w", key, err) } // Fsck verifies the connectivity and validity of the objects in the database diff --git a/modules/git/git_test.go b/modules/git/git_test.go index c62a55badc..5b1cd820e8 100644 --- a/modules/git/git_test.go +++ b/modules/git/git_test.go @@ -8,23 +8,74 @@ import ( "context" "fmt" "os" + "strings" "testing" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" ) -func fatalTestError(fmtStr string, args ...interface{}) { - fmt.Fprintf(os.Stderr, fmtStr, args...) - os.Exit(1) +func testRun(m *testing.M) error { + _ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`) + + repoRootPath, err := os.MkdirTemp(os.TempDir(), "repos") + if err != nil { + return fmt.Errorf("unable to create temp dir: %w", err) + } + defer util.RemoveAll(repoRootPath) + setting.RepoRootPath = repoRootPath + + if err = InitWithConfigSync(context.Background()); err != nil { + return fmt.Errorf("failed to call Init: %w", err) + } + + exitCode := m.Run() + if exitCode != 0 { + return fmt.Errorf("run test failed, ExitCode=%d", exitCode) + } + return nil } func TestMain(m *testing.M) { - _ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`) + if err := testRun(m); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Test failed: %v", err) + os.Exit(1) + } +} - if err := Init(context.Background()); err != nil { - fatalTestError("Init failed: %v", err) +func TestGitConfig(t *testing.T) { + gitConfigContains := func(sub string) bool { + if b, err := os.ReadFile(HomeDir() + "/.gitconfig"); err == nil { + return strings.Contains(string(b), sub) + } + return false } - exitStatus := m.Run() - os.Exit(exitStatus) + assert.False(t, gitConfigContains("key-a")) + + assert.NoError(t, configSetNonExist("test.key-a", "val-a")) + assert.True(t, gitConfigContains("key-a = val-a")) + + assert.NoError(t, configSetNonExist("test.key-a", "val-a-changed")) + assert.False(t, gitConfigContains("key-a = val-a-changed")) + + assert.NoError(t, configSet("test.key-a", "val-a-changed")) + assert.True(t, gitConfigContains("key-a = val-a-changed")) + + assert.NoError(t, configAddNonExist("test.key-b", "val-b")) + assert.True(t, gitConfigContains("key-b = val-b")) + + assert.NoError(t, configAddNonExist("test.key-b", "val-2b")) + assert.True(t, gitConfigContains("key-b = val-b")) + assert.True(t, gitConfigContains("key-b = val-2b")) + + assert.NoError(t, configUnsetAll("test.key-b", "val-b")) + assert.False(t, gitConfigContains("key-b = val-b")) + assert.True(t, gitConfigContains("key-b = val-2b")) + + assert.NoError(t, configUnsetAll("test.key-b", "val-2b")) + assert.False(t, gitConfigContains("key-b = val-2b")) } diff --git a/modules/git/lfs.go b/modules/git/lfs.go index cdd9d15b2e..c5d8354b6d 100644 --- a/modules/git/lfs.go +++ b/modules/git/lfs.go @@ -18,12 +18,6 @@ func CheckLFSVersion() { if setting.LFS.StartServer { // Disable LFS client hooks if installed for the current OS user // Needs at least git v2.1.2 - - err := LoadGitVersion() - if err != nil { - logger.Fatal("Error retrieving git version: %v", err) - } - if CheckGitVersionAtLeast("2.1.2") != nil { setting.LFS.StartServer = false logger.Error("LFS server support needs at least Git v2.1.2") diff --git a/modules/git/remote.go b/modules/git/remote.go index 536b1681ce..b2a2e6d7ab 100644 --- a/modules/git/remote.go +++ b/modules/git/remote.go @@ -11,10 +11,6 @@ import ( // GetRemoteAddress returns the url of a specific remote of the repository. func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) { - err := LoadGitVersion() - if err != nil { - return nil, err - } var cmd *Command if CheckGitVersionAtLeast("2.7") == nil { cmd = NewCommand(ctx, "remote", "get-url", remoteName) diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go index a18c80c3f1..38818788f3 100644 --- a/modules/git/repo_attribute.go +++ b/modules/git/repo_attribute.go @@ -28,11 +28,6 @@ type CheckAttributeOpts struct { // CheckAttribute return the Blame object of file func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[string]string, error) { - err := LoadGitVersion() - if err != nil { - return nil, fmt.Errorf("git version missing: %v", err) - } - env := []string{} if len(opts.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil { @@ -126,7 +121,7 @@ type CheckAttributeReader struct { cancel context.CancelFunc } -// Init initializes the cmd +// Init initializes the CheckAttributeReader func (c *CheckAttributeReader) Init(ctx context.Context) error { cmdArgs := []string{"check-attr", "--stdin", "-z"} diff --git a/modules/git/repo_tree.go b/modules/git/repo_tree.go index 3e7a9c2cfb..2e139daddf 100644 --- a/modules/git/repo_tree.go +++ b/modules/git/repo_tree.go @@ -24,11 +24,6 @@ type CommitTreeOpts struct { // CommitTree creates a commit from a given tree id for the user with provided message func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) { - err := LoadGitVersion() - if err != nil { - return SHA1{}, err - } - commitTimeStr := time.Now().Format(time.RFC3339) // Because this may call hooks we should pass in the environment @@ -60,14 +55,13 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) - err = cmd.Run(&RunOpts{ + err := cmd.Run(&RunOpts{ Env: env, Dir: repo.Path, Stdin: messageBytes, Stdout: stdout, Stderr: stderr, }) - if err != nil { return SHA1{}, ConcatenateError(err, stderr.String()) } diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index 9d9de5413c..a335972c21 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -30,7 +30,7 @@ func TestMain(m *testing.M) { } func TestRepoStatsIndex(t *testing.T) { - if err := git.Init(context.Background()); !assert.NoError(t, err) { + if err := git.InitWithConfigSync(context.Background()); !assert.NoError(t, err) { return } diff --git a/modules/repository/init.go b/modules/repository/init.go index f8c7a89552..285fe81dbe 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -317,11 +317,6 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi return fmt.Errorf("git add --all: %v", err) } - err = git.LoadGitVersion() - if err != nil { - return fmt.Errorf("Unable to get git version: %v", err) - } - args := []string{ "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", "Initial commit", diff --git a/modules/util/path.go b/modules/util/path.go index ed7cc62699..0ccc7a1dc2 100644 --- a/modules/util/path.go +++ b/modules/util/path.go @@ -182,6 +182,7 @@ func FileURLToPath(u *url.URL) (string, error) { // it returns error when the variable does not exist. func HomeDir() (home string, err error) { // TODO: some users run Gitea with mismatched uid and "HOME=xxx" (they set HOME=xxx by environment manually) + // TODO: when running gitea as a sub command inside git, the HOME directory is not the user's home directory // so at the moment we can not use `user.Current().HomeDir` if isOSWindows() { home = os.Getenv("USERPROFILE") diff --git a/routers/init.go b/routers/init.go index 6036499362..9b6a770f27 100644 --- a/routers/init.go +++ b/routers/init.go @@ -102,8 +102,8 @@ func GlobalInitInstalled(ctx context.Context) { log.Fatal("Gitea is not installed") } - mustInitCtx(ctx, git.Init) - log.Info(git.VersionInfo()) + mustInitCtx(ctx, git.InitWithConfigSync) + log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir()) git.CheckLFSVersion() log.Info("AppPath: %s", setting.AppPath) diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 78347e67c4..24c07b5c1c 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -247,9 +247,8 @@ func Config(ctx *context.Context) { ctx.Data["DisableRouterLog"] = setting.DisableRouterLog ctx.Data["RunUser"] = setting.RunUser ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode) - if version, err := git.LocalVersion(); err == nil { - ctx.Data["GitVersion"] = version.Original() - } + ctx.Data["GitVersion"] = git.VersionInfo() + ctx.Data["RepoRootPath"] = setting.RepoRootPath ctx.Data["CustomRootPath"] = setting.CustomPath ctx.Data["StaticRootPath"] = setting.StaticRootPath diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go index 7c2ff1cfae..e2421f1389 100644 --- a/routers/web/repo/lfs.go +++ b/routers/web/repo/lfs.go @@ -421,12 +421,9 @@ func LFSPointerFiles(ctx *context.Context) { return } ctx.Data["PageIsSettingsLFS"] = true - err := git.LoadGitVersion() - if err != nil { - log.Fatal("Error retrieving git version: %v", err) - } ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs" + var err error err = func() error { pointerChan := make(chan lfs.PointerBlob) errChan := make(chan error, 1) diff --git a/services/pull/merge.go b/services/pull/merge.go index fcced65cdf..76798d73ed 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -223,12 +223,6 @@ func Merge(ctx context.Context, pr *models.PullRequest, doer *user_model.User, b // rawMerge perform the merge operation without changing any pull information in database func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (string, error) { - err := git.LoadGitVersion() - if err != nil { - log.Error("git.LoadGitVersion: %v", err) - return "", fmt.Errorf("Unable to get git version: %v", err) - } - // Clone base repo. tmpBasePath, err := createTemporaryRepo(ctx, pr) if err != nil { diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go index 9c7d9aafec..97a80a96bd 100644 --- a/services/repository/files/temp_repo.go +++ b/services/repository/files/temp_repo.go @@ -229,11 +229,6 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, co authorSig := author.NewGitSig() committerSig := committer.NewGitSig() - err := git.LoadGitVersion() - if err != nil { - return "", fmt.Errorf("Unable to get git version: %v", err) - } - // Because this may call hooks we should pass in the environment env := append(os.Environ(), "GIT_AUTHOR_NAME="+authorSig.Name, From 5f618248a98ffbb7066100ffe1955faf791d0205 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 10 Jun 2022 11:34:41 +0800 Subject: [PATCH 3/3] Use Golang 1.18 for Gitea 1.17 release (#19918) Use Golang 1.18 (as minimal requirement) for Gitea 1.17 release, make sure the Golang version is still actively supported during Gitea 1.17 lifecycle. Co-authored-by: zeripath Co-authored-by: Lunny Xiao Co-authored-by: 6543 <6543@obermui.de> --- .drone.yml | 2 +- README.md | 2 +- docs/config.yaml | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 4 ++-- go.mod | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 1aac10a828..928e75d1ac 100644 --- a/.drone.yml +++ b/.drone.yml @@ -109,7 +109,7 @@ steps: depends_on: [test-frontend] - name: build-backend-no-gcc - image: golang:1.17 # this step is kept as the lowest version of golang that we support + image: golang:1.18 # this step is kept as the lowest version of golang that we support pull: always environment: GO111MODULE: on diff --git a/README.md b/README.md index 84c0524ed4..172e16cf56 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ or if SQLite support is required: The `build` target is split into two sub-targets: -- `make backend` which requires [Go 1.17](https://go.dev/dl/) or greater. +- `make backend` which requires [Go Stable](https://go.dev/dl/), required version is defined in [go.mod](/go.mod). - `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js and Internet connectivity. diff --git a/docs/config.yaml b/docs/config.yaml index 075fd32ef4..5a773662cf 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -19,7 +19,7 @@ params: author: The Gitea Authors website: https://docs.gitea.io version: 1.16.8 - minGoVersion: 1.17 + minGoVersion: 1.18 goVersion: 1.18 minNodeVersion: 14 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index edd23012fb..3981dc5fab 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -315,8 +315,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `SSL_MAX_VERSION`: **\**: Set the maximum version of ssl support. - `SSL_CURVE_PREFERENCES`: **X25519,P256**: Set the preferred curves, - `SSL_CIPHER_SUITES`: **ecdhe_ecdsa_with_aes_256_gcm_sha384,ecdhe_rsa_with_aes_256_gcm_sha384,ecdhe_ecdsa_with_aes_128_gcm_sha256,ecdhe_rsa_with_aes_128_gcm_sha256,ecdhe_ecdsa_with_chacha20_poly1305,ecdhe_rsa_with_chacha20_poly1305**: Set the preferred cipher suites. - - If there is not hardware support for AES suites by default the cha cha suites will be preferred over the AES suites - - supported suites as of go 1.17 are: + - If there is no hardware support for AES suites, by default the ChaCha suites will be preferred over the AES suites. + - supported suites as of Go 1.18 are: - TLS 1.0 - 1.2 cipher suites - "rsa_with_rc4_128_sha" - "rsa_with_3des_ede_cbc_sha" diff --git a/go.mod b/go.mod index 4dea7f9423..e7cb85ad1b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.gitea.io/gitea -go 1.17 +go 1.18 require ( code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b