Go lintpack: مدير اللنت القابل للتركيب


lintpack هي أداة مفيدة لبناء اللنتر (المحللون الاستاتيكيون) ، والتي تتم كتابتها باستخدام واجهة برمجة التطبيقات المتوفرة. بناءً على ذلك ، يتم الآن إعادة كتابة المحلل الثابت للنقد ، المألوف لدى البعض.


اليوم lintpack بمزيد من التفصيل ما lintpack من وجهة نظر المستخدم.


في البداية كان الناقد ...


بدأ الناقد كمشروع تجريبي كان بمثابة وضع حماية للنماذج الأولية لأي أفكار تحليل ثابتة لـ Go.


كانت المفاجأة السارة أن بعض الأشخاص أرسلوا تطبيقات للكشف عن مشاكل مختلفة في الكود. كان كل شيء تحت السيطرة حتى بدأ الدين التقني في التراكم ، والذي لم يكن هناك من يستغني عنه عمليا. جاء الناس ، وأضافوا التحقق ، ثم اختفوا. ثم من الذي عليه تصحيح الأخطاء وتعديل التنفيذ؟


كان من الأحداث الهامة اقتراح إضافة عمليات التحقق التي تتطلب تكوينًا إضافيًا ، أي تلك التي تعتمد على الترتيبات المحلية للمشروع. أحد الأمثلة هو الكشف عن وجود رأس حقوق طبع ونشر في ملف (رأس ترخيص) باستخدام قالب خاص أو حظر استيراد بعض الحزم مع اقتراح بديل معين.


الصعوبة الأخرى كانت التمدد. ليس من المناسب للجميع إرسال رمزهم إلى مستودع شخص آخر. أراد البعض ربط الشيكات ديناميكيًا بحيث لا يحتاجون إلى تعديل رموز مصدر go-critic .


الخلاصة ، فيما يلي المشاكل التي تقف في طريق تطوير go-critic :


  • حمولة من التعقيد. الكثير من الدعم ، وجود رمز بدون مالك.
  • جودة متوسطة منخفضة. يعني experimental "جاهز تقريبًا للاستخدام" و "الأفضل ألا يعمل على الإطلاق".
  • في بعض الأحيان يكون من الصعب تحديد ما إذا كان سيتم تضمين التحقق في go-critic ، ورفضها يتعارض مع فلسفة التصميم الأصلية.
  • رأى الناس مختلفين go-critic مختلف. أراد معظمهم الحصول عليه باعتباره gometalinter ، والذي يأتي مع gometalinter .

من أجل الحد من عدد التناقضات والتفسيرات غير المتسقة للمشروع بطريقة ما ، تم كتابة بيان .


إذا كنت تريد سياقًا تاريخيًا إضافيًا ومزيدًا من التفكير في تصنيف المحللات الثابتة ، فيمكنك الاستماع إلى تسجيل GoCritic ، وهو محلل ثابت جديد لـ Go . في تلك اللحظة ، لم تكن lintpack موجودة بعد ، ولكن بعض الأفكار ولدت في ذلك اليوم ، بعد التقرير.

ولكن ماذا لو لم نكن بحاجة إلى تخزين جميع الشيكات في مستودع واحد؟


تلبية - lintpack




يتكون go-critic من مكونين رئيسيين:


  1. تنفيذ الشيكات بأنفسهم.
  2. برنامج يقوم بتنزيل حزم التحقق من الصحة Go ويقوم بتشغيل عمليات التحقق منها.

هدفنا: أن نكون قادرين على تخزين الشيكات للليتر في مستودعات مختلفة وجمعها معًا عند الضرورة.


lintpack يفعل ذلك فقط. وهي تحدد الوظائف التي تسمح لك بوصف الشيكات الخاصة بك بطريقة يمكنك بعد ذلك تشغيلها من خلال اللتر الذي تم إنشاؤه.


تسمى الحزم التي يتم تنفيذها باستخدام lintpack كإطار عمل lintpack متوافقة مع lintpack أو متوافقة مع lintpack .

إذا تم تنفيذ go-critic على أساس lintpack ، يمكن تقسيم جميع الشيكات إلى عدة مستودعات. قد يكون أحد خيارات الفصل ما يلي:


  1. المجموعة الرئيسية حيث تحصل جميع الشيكات المستقرة والمدعومة.
  2. ساهم بمستودع حيث يكون الكود إما تجريبيًا جدًا أو يفتقر إلى مشرف.
  3. فحوصات قابلة للتخصيص لمشروع محدد.

النقطة الأولى ذات أهمية خاصة فيما يتعلق بدمج الناقد في golangci-lint .


إذا بقيت على مستوى go-critic ، فلن يتغير شيء تقريبًا للمستخدمين. lintpack متطابق تقريبًا ، في حين أن golangci-lint جميع تفاصيل التنفيذ المختلفة.


لكن شيئاً ما تغير. إذا تم إنشاء lintpack جديدة على أساس lintpack ، فسيكون لديك مجموعة أكثر ثراء من التشخيصات الجاهزة لتوليد اللتر. تخيل للحظة أن الأمر كذلك ، وهناك أكثر من 10 مجموعات مختلفة من الشيكات في العالم.


بداية سريعة



للبدء ، تحتاج إلى تثبيت lintpack نفسه:


 # lintpack    `$(go env GOPATH)/bin`. go get -v github.com/go-lintpack/lintpack/... 

قم بإنشاء linter باستخدام حزمة الاختبار من lintpack :


 lintpack build -o mylinter github.com/go-lintpack/lintpack/checkers 

تتضمن المجموعة panicNil ، التي تجد panic(nil) في التعليمات البرمجية وتطلب استبدالها بشيء مميز ، وإلا لن يتمكن recover() من معرفة ما إذا كان panic تم استدعاؤه بحجة nil ، أو لم يكن هناك ذعر على الإطلاق.


مثال مع ذعر (لا شيء)


يحاول الرمز أدناه وصف القيمة التي تم الحصول عليها من recover() :


 r := recover() fmt.Printf("%T, %v\n", r, r) 

ستكون النتيجة مماثلة panic(nil) التي لا panic(nil) .


مثال على السلوك الموصوف .




يمكنك بدء اللنتر على ملفات منفصلة ، بحجج من النوع ./... أو الحزم (حسب مسار الاستيراد).


 ./mylinter check bytes $GOROOT/src/bytes/buffer_test.go:276:3: panicNil: panic(nil) calls are discouraged 

 #   ,  go-lintpack    $GOPATH. mylinter=$(pwd)/mylinter cd $(go env GOPATH)/src/github.com/go-lintpack/lintpack/checkers/testdata $mylinter check ./panicNil/ ./panicNil/positive_tests.go:5:3: panicNil: panic(nil) calls are discouraged ./panicNil/positive_tests.go:9:3: panicNil: panic(interface{}(nil)) calls are discouraged 

بشكل افتراضي ، يستجيب هذا الفحص أيضًا panic(interface{}(nil)) . لتجاوز هذا السلوك ، قم بتعيين skipNilEfaceLit على true . يمكنك القيام بذلك من خلال سطر الأوامر:


 $mylinter check -@panicNil.skipNilEfaceLit=true ./panicNil/ ./panicNil/positive_tests.go:5:3: panicNil: panic(nil) calls are discouraged 

استخدام ل cmd / lintpack و linter ولدت


lintpack كل من lintpack و lintpack الناتج الوسيطة الأولى لتحديد أمر فرعي. يمكن الحصول على قائمة الأوامر الفرعية المتاحة وأمثلة على إطلاقها عن طريق استدعاء الأداة المساعدة بدون وسيطات.


 lintpack not enough arguments, expected sub-command name Supported sub-commands: build - build linter from made of lintpack-compatible packages $ lintpack build -help $ lintpack build -o gocritic github.com/go-critic/checkers $ lintpack build -linter.version=v1.0.0 . version - print lintpack version $ lintpack version 

لنفترض أننا أطلقنا على اسم gocritic تم إنشاؤه باسم gocritic :


 ./gocritic not enough arguments, expected sub-command name Supported sub-commands: check - run linter over specified targets $ linter check -help $ linter check -disableTags=none strings bytes $ linter check -enableTags=diagnostic ./... version - print linter version $ linter version doc - get installed checkers documentation $ linter doc -help $ linter doc $ linter doc checkerName 

علامة -help متاحة لبعض الأوامر الفرعية ، والتي توفر معلومات إضافية (أقوم بقص بعض الخطوط العريضة جدًا):


 ./gocritic check -help #     . 



توثيق الشيكات المثبتة


الجواب على السؤال "كيف تعرف عن معلمة skipNilEfaceLit؟" - قراءة دليل الهوى (RTFM)!


جميع الوثائق حول الشيكات المثبتة داخل mylinter . هذه الوثائق متاحة من خلال الأمر الفرعي doc :


 #     : $mylinter doc panicNil [diagnostic] #      : $mylinter doc panicNil panicNil checker documentation URL: github.com/go-lintpack/lintpack Tags: [diagnostic] Detects panic(nil) calls. Such panic calls are hard to handle during recover. Non-compliant code: panic(nil) Compliant code: panic("something meaningful") Checker parameters: -@panicNil.skipNilEfaceLit bool whether to ignore interface{}(nil) arguments (default false) 

مثل دعم القوالب في go list -f ، يمكنك تمرير سطر قالب مسؤول عن تنسيق الإخراج للوثائق ، والذي يمكن أن يكون مفيدًا عند كتابة مستندات تخفيض السعر.


أين تبحث عن شيكات التثبيت؟


لتبسيط البحث عن مجموعات lintpack المفيدة ، هناك قائمة مركزية من الحزم المتوافقة مع lintpack : https://go-lintpack.imtqy.com/ .


إليك بعض القائمة:



يتم تحديث هذه القائمة بشكل دوري وهي مفتوحة لطلبات الإضافة. يمكن استخدام أي من هذه الحزم لإنشاء اللتر.


يقوم الأمر أدناه بإنشاء لنتر يحتوي على كافة عمليات التحقق من القائمة أعلاه:


 #   ,      #   Go . go get -v github.com/go-critic/go-critic/checkers go get -v github.com/go-critic/checkers-contrib # build   . lintpack build \ github.com/go-critic/go-critic/checkers \ github.com/go-critic/checkers-contrib 

يتضمن lintpack build جميع الفحوصات في مرحلة التجميع ، ويمكن وضع lintpack build الناتج في بيئة لا توجد فيها رموز مصدر لتنفيذ التشخيصات المثبتة ، وكل شيء على النحو المعتاد مع الربط الثابت.


مرفق الحزمة الديناميكية


بالإضافة إلى التجميع الثابت ، من الممكن تحميل الإضافات التي توفر فحوصات إضافية.


تكمن الخصوصية في أن تطبيق المدقق لا يعرف ما إذا كان سيتم استخدامه لتجميع ثابت أو سيتم تحميله كمكون إضافي. مطلوب أي تغييرات على الرمز.


لنفترض أننا نريد إضافة panicNil إلى panicNil ، لكننا لسنا قادرين على إعادة بنائه من جميع المصادر التي تم استخدامها أثناء التجميع الأول.


  1. قم linterPlugin.go :

 package main //         , //    import'. import ( _ "github.com/go-lintpack/lintpack/checkers" ) 

  1. بناء مكتبة ديناميكية:

 go build -buildmode=plugin -o linterPlugin.so linterPlugin.go 

  1. قم بتشغيل -pluginPath مع المعلمة -pluginPath :

 ./linter check -pluginPath=linterPlugin.so bytes 

تحذير: يتم تنفيذ دعم الوحدات الديناميكية من خلال حزمة مكون إضافي لا تعمل على Windows.

يمكن أن تساعدك علامة -verbose معرفة أي فحص قيد التشغيل أو إيقاف تشغيله ، والأهم من ذلك أنها ستعرض الفلتر الذي عطّل الفحص.


مثال مع -verbose


لاحظ أنه panicNil عرض panicNil في قائمة الاختبارات المضمنة. إذا قمنا بإزالة الوسيطة -pluginPath ، فسوف تتوقف عن صحتها.


 ./linter check -verbose -pluginPath=./linterPlugin.so bytes debug: appendCombine: disabled by tags (-disableTags) debug: boolExprSimplify: disabled by tags (-disableTags) debug: builtinShadow: disabled by tags (-disableTags) debug: commentedOutCode: disabled by tags (-disableTags) debug: deprecatedComment: disabled by tags (-disableTags) debug: docStub: disabled by tags (-disableTags) debug: emptyFallthrough: disabled by tags (-disableTags) debug: hugeParam: disabled by tags (-disableTags) debug: importShadow: disabled by tags (-disableTags) debug: indexAlloc: disabled by tags (-disableTags) debug: methodExprCall: disabled by tags (-disableTags) debug: nilValReturn: disabled by tags (-disableTags) debug: paramTypeCombine: disabled by tags (-disableTags) debug: rangeExprCopy: disabled by tags (-disableTags) debug: rangeValCopy: disabled by tags (-disableTags) debug: sloppyReassign: disabled by tags (-disableTags) debug: typeUnparen: disabled by tags (-disableTags) debug: unlabelStmt: disabled by tags (-disableTags) debug: wrapperFunc: disabled by tags (-disableTags) debug: appendAssign is enabled debug: assignOp is enabled debug: captLocal is enabled debug: caseOrder is enabled debug: defaultCaseOrder is enabled debug: dupArg is enabled debug: dupBranchBody is enabled debug: dupCase is enabled debug: dupSubExpr is enabled debug: elseif is enabled debug: flagDeref is enabled debug: ifElseChain is enabled debug: panicNil is enabled debug: regexpMust is enabled debug: singleCaseSwitch is enabled debug: sloppyLen is enabled debug: switchTrue is enabled debug: typeSwitchVar is enabled debug: underef is enabled debug: unlambda is enabled debug: unslice is enabled # ...   . 



مقارنة مع gometalinter و golangci-lint


من أجل تجنب الارتباك ، يجدر وصف الاختلافات الرئيسية بين المشاريع.


gometalinter و golangci-lint يدمجان في الأساس موادًا أخرى ، غالبًا ما يتم تنفيذها بشكل مختلف تمامًا ، توفر إمكانية وصول مريحة إليها. تستهدف المستخدمين النهائيين الذين سيستخدمون أجهزة تحليل ثابتة.


يبسط lintpack إنشاء عتبات جديدة ، ويوفر إطار عمل يجعل الحزم المختلفة ، التي يتم تنفيذها على أساسها ، متوافقة مع نفس الملف القابل للتنفيذ. يمكن بعد ذلك تضمين عمليات التحقق هذه (لـ golangci-lint) أو الملف القابل للتنفيذ (لـ gometalinter) في meta-linters المذكورة أعلاه.


افترض أن أحد الشيكات المتوافقة مع lintpack هو جزء من golangci-lint . إذا كانت هناك أي مشكلة تتعلق golangci-lint للاستخدام ، فقد تكون هذه مسؤولية golangci-lint ، ولكن إذا كان من الخطأ تنفيذ التحقق نفسه ، فهذه هي مشكلة مؤلفي التحقق ، lintpack ، النظام البيئي.


وبعبارة أخرى ، تحل هذه المشاريع مشاكل مختلفة.


ماذا عن الناقد؟


lintpack عملية نقل go-critic إلى lintpack ؛ يمكن العثور على الداما في مستودع الناقد / الداما .


 #  go-critic : go get -v github.com/go-critic/go-critic/... #  go-critic : lintpack -o gocritic github.com/go-critic/go-critic/checkers 

من غير المنطقي استخدام go-critic خارج golangci-lint ، ولكن lintpack يمكن أن يسمح لك بتثبيت تلك الشيكات غير المدرجة في go-critic . على سبيل المثال ، قد تكون هذه التشخيصات التي كتبتها.


يتبع


سوف تتعلم كيفية إنشاء lintpack المتوافقة مع lintpack في المقالة التالية.


هناك سنقوم بتحليل المزايا التي تحصل عليها عند تنفيذ اللنتر القائم على lintpack مقارنة بالتنفيذ من البداية.


آمل أن يكون لديك شهية لإجراء فحوصات جديدة لـ Go. اسمحوا لي أن أعرف كم يصبح التحليل الثابت أكثر من اللازم ، وسنعمل على حل هذه المشكلة معًا بسرعة.

Source: https://habr.com/ru/post/ar430196/


All Articles