Simpletask/commandrunnerinspiredbymakewithdeclarativegoalsanddependencies.
Thesimplestwaytothinkofthistoolistohaveawaytohave"shortcuts"(akagoals)tosomepiecesofscripts.Thiswayallowstocallthemeasilywithouttheneedtocalllongshellone-linersinstead.
ExampleMakesurefile:
@goaldownloaded@reached_if[[-fcode.tar.gz]]wgethttps://domain/code.tar.gz@goalextracted@depends_ondownloadedtarxzfcode.tar.gz@goalbuilt@depends_onextractednpminstallnpmrunbuild@goaldeployed@depends_onbuiltscp-C-rbuild/*user@domain:~/www@goaldefault@depends_ondeployedNowtorunthewholebuildyoujustissue./makesurecommandinafolderwithMakesurefile(defaultgoalwillbecalled).
Youcanaswellcallsinglegoalexplicitly,example./makesurebuilt.
Alsopayattentionto@reached_ifdirective.Thisoneallowsskippinggoalifit'salreadysatisfied.Thisallowstospeedupsubsequentexecutions.
Bydefault,allscriptsinsidegoalsareexecutedwithbash.Ifyouwanttouseshjustadd@shellshdirectiveatstartoftheMakesurefile.
FeaturesZero-installVeryportableVerysimple,onlybareminimumoftrulyneededfeatures.Youdon’tneedtolearnawholenewprogramminglanguagetousethetool!Literallyit’sgoals+dependencies+handfulofdirectives+bash/shell.Muchsanerandsimplermakeanalog.Abunchofusefulbuilt-infacilities:timingthegoal'sexecution,listinggoalsinabuildfile,ameanstospeed-uprepeatedbuilds.Thesyntaxofabuildfileisalsoavalidbash/shell(thoughsemanticsisdifferent).ThiscantosomeextentbeinuseforeditinginIDE.Usage$./makesure-hmakesurever.0.9.13Usage:makesure[options...][-fbuildfile][goals...]-f,--filebuildfilesetbuildfiletouse(defaultMakesurefile)-l,--listlistallavailablenon-@privategoals-la,--list-alllistallavailablegoals-d,--resolvedlistresolveddependenciestoreachgivengoals-D"var=val",--define"var=val"override@definevalues-s,--silentsilentmode-onlyoutputwhatgoalsoutput-t,--timingdisplayexecutiontimesforgoalsandtotal-x,--tracingenabletracinginbash/shvia`set-x`-v,--versionprintversionandexit-h,--helpprinthelpandexit-U,--selfupdateupdatemakesuretolatestversionInstallationSincemakesureisatinyutilityrepresentedbyasinglefile,therecommendedinstallationstrategyistokeepitlocaltoaprojectwhereit'sused(thismeansincoderepository).Notonlythiseliminatestheneedforrepetitiveinstallationforeverydevonaproject,butalsoallowsusingseparatemakesureversionperprojectandupdateonlyasneeded.
wget"https://raw.githubusercontent.com/xonixx/makesure/main/makesure?token=$(date+%s)"-Omakesure&&\chmod+xmakesure&&echo"makesure$(./makesure-v)installed"UpdateUpdatesmakesureexecutabletolatestavailableversionin-place:
./makesure-UPrerequisitesOSmakesurewillrunonanyenvironmentwithPosixshellavailable.Testedandofficiallysupportedare:
LinuxMacOSWindows(viaGitBash)AWKThecoreofthistoolisimplementedinAWK.AlmostallmajorimplementationsofAWKwillwork.TestedandofficiallysupportedareGawk,BWK,mawk.ThismeansthatthedefaultAWKimplementationinyourOSwillwork.
ThetoolwillnotworkwithBusyboxawk.
ConceptsBuildfileisatextfilenamedMakesurefile.Buildfileconsistsofapreludeandasetofgoals.Buildfileusesdirectives.Preludeisapieceofashellscript(canbeempty)thatgoesbeforegoals.Thepurposeofpreludeisto@define(link)globalvariablesvisibletogoals.Preludeonlyrunsonce.Agoalisalabeledpieceofshell.Agoalcandeclaredependenciesonothergoals.Duringexecutioneachreferenceddependencywillrunonlyoncedespitethenumberofoccurrencesindependencytree.Dependencieswillruninproperorderaccordingtotheinferredtopologicalorder.Dependencyloopswillbereportedaserror.Goalbodiesareexecutedinseparateshellinvocations.Itmeans,youcan’teasilypassvariablesfromonegoaltoanother.Thisisdoneonpurposetoenforcedeclarativestyle.Bydefault,bothpreludeandgoalsarerunwithbash.Youcanchangetoshwith@shellshinprelude.Forconvenienceinallshellinvocations(prelude,goals,etc.)thecurrentdirectoryisautomaticallysettotheoneofMakesurefile.Typically,thisistherootoftheproject.Thisallowsusingrelativepathswithoutbotheringofthewaythebuildisrun.Goalcandeclare@reached_ifdirective(link).Thisallowsskippinggoalexecutionifit'salreadysatisfied.Directives@optionsOnlyvalid:inprelude(meaningbeforeany@goaldeclaration).
Validoptions:timing,tracing,silent
@optionstimingWillmeasureandlogeachgoalexecutiontime+totaltime.
ExampleMakesurefile:
@optionstiming@goala@depends_onbecho"Executinggoal'a'..."sleep1@goalbecho"Executinggoal'b'..."sleep2Running:
$./makesureagoal'b'...Executinggoal'b'...goal'b'took2.003sgoal'a'...Executinggoal'a'...goal'a'took1.003stotaltime3.006sSmallissueexistswiththisoptiononmacOS.DuetoBSD'sdatenotsupporting+%Nformattingoption,thedefaultprecisionoftimingsis1sec.Tomakeit1msprecise(ifthisisimportant)justinstallGawk(brewinstallgawk).InthiscaseGawkbuilt-ingettimeofdayfunctionwillbeused.
@optionstracingWilltracetheexecutedshellscript.Thisactivatesset-xshelloptionunderthehood.
@optionssilentBydefaultmakesurelogsthegoalsbeingexecuted.Usethisoptionifthisisnotdesired(youonlyneedtheoutputofyourowncodeingoals).
@defineOnlyvalid:inprelude.
Usethisdirectivetodeclareglobalvariable(visibletoallgoals).Thevariablewillbedeclaredasenvironmentvariable(viaexport).
Example:
@defineA=hello@defineB="${A}world"Variabledefinedwith@definecanbeoverriddenwithavariablepassedininvocationvia-Dparameter.
Overalltheprecedenceforvariablesresolutionis(higherprioritytop):
./makesure-DVAR=1@defineVAR=2inMakesurefileVAR=3./makesure@shellOnlyvalid:inprelude.
Validoptions:bash(default),sh
Setstheshellinterpretertobeusedforexecutionofpreludeandgoals.
Example:
@shellsh@goalSyntax#1:
@goalgoal_name[@private]Definesagoal.@privatemodifierisoptional.Whengoalisprivate,itwon'tshowin./makesure-l.Tolistallgoalsincludingprivateuse./makesure-la.
Linesthatgoafterthisdeclarationline(butbeforenext@goaldeclarationline)willbetreatedasashellscriptforthebodyofthegoal.Example:
@goalhelloecho"Helloworld"HavingtheaboveinMakesurefilewillproducenextoutputwhenranwith./makesurehello
helloworldIndentationingoalbodyisoptional,unlikemake,sobelowisperfectlyvalid:
@goalhelloecho"Helloworld"Invoking./makesurewithoutargumentswillattempttocallthegoalnameddefault:
@goaldefaultecho"I'mdefaultgoal"Syntax#2:
@goal[goal_name]@glob<globpattern>[@private]Thisoneiseasytoillustratewithanexample:
@goalprocess_file@glob*.txtecho$ITEM$INDEX$TOTALIsequivalenttodeclaringthreegoals
@goalprocess_file@a.txt@privateechoa.txt02@goalprocess_file@b.txt@privateechob.txt12@goalprocess_file@depends_onprocess_file@a.txt@depends_onprocess_file@b.txtiff
$lsa.txtb.txtForconvenience,youcanomitnameincaseofglobgoal:
@goal@glob*.txtecho$ITEM$INDEX$TOTALasequivalentfor
@goala.txt@privateechoa.txt02@goalb.txt@privateechob.txt12@goal*.txt@depends_ona.txt@depends_onb.txtSoessentiallyoneglobgoaldeclarationexpandstomultiplegoaldeclarationsbasedonfilespresentinprojectthatmatchtheglobpattern.Shellglobexpansionmechanismapplies.
Theusefulusecaseherewouldbetorepresentasetoftestfilesasasetofgoals.Theexamplecouldbefoundintheproject'sownbuildfile.
Whythismaybeuseful?Imagineinyournodejsapplicationyouhavetest1.js,test2.js,test3.js.NowyoucanusethisMakesurefile
@goal@globtest*.jsecho"runningtestfile$INDEXoutof$TOTAL..."node$ITEMtobeabletoruneachtestindividually(./makesuretest2.jsforexample)andalltogether(./makesure'test*.js').
Incaseifyouneedtoglobthefileswithspacesintheirnames,pleasecheckthenamingrulessectionbelow.
@docOnlyvalid:inside@goal.
Providesadescriptionforagoal.
ExampleMakesurefile:
@goalbuild@docbuildstheprojectecho"Building..."@goaltest@docteststheprojectecho"Testing..."Running./makesure-lwillshow
Availablegoals:build:buildstheprojecttest:teststheproject@depends_onOnlyvalid:inside@goal.
Syntax:
@depends_ongoal1[goal2[goal3[...]]]Declaresadependencyonothergoal.
ExampleMakesurefile:
@goalaechoa@goalb@depends_onaechobRunning./makesurebwillshow
goal'a'...agoal'b'...bYoucandeclaremultipledependenciesforagoal:
@goalaechoa@goalb@depends_onaechob@goalcechoc@goald@depends_onbcechodRunning./makesuredwillshow
goal'a'...agoal'b'...bgoal'c'...cgoal'd'...dCirculardependencywillcauseanerror:
@goala@depends_onb@goalb@depends_onc@goalc@depends_onaRunning./makesureawillshow
Thereisaloopingoaldependenciesviaa->c@reached_ifOnlyvalid:inside@goal.
Syntax:
@reached_if<condition>Allowsskippinggoalexecutionifit'salreadysatisfied.Thisallowstospeedupsubsequentexecutions.Onlyonepergoalallowed.Thegoalwillbeconsideredfulfilled(andthuswillnotrun)ifconditionexecutedasashellscriptreturnsexitcode0.Anyconditionevaluationisdoneonlyonce.
ExampleMakesurefile:
@goalfile_created@reached_if[[-f./file.txt]]echo"Creatingfile..."echo"helloworld">./file.txtIfyourun./makesurefile_createdthefirsttime:
goal'file_created'...Creatingfile...Ifyourun./makesurefile_createdthesecondtime:
goal'file_created'[alreadysatisfied].Itisagoodpracticetonamegoalsthatdeclare@reached_ifinpasttense.
@libSyntax:
@lib[lib_name]Helpswithcodereuse.Occasionallyyouneedtorunsimilarcodeinmultiplegoals.Themostobviousapproachwouldbetoplaceacodeintoshared.shandinvokeitinbothgoals.Thedownsideisthatnowyouneedanadditionalfile(s)andthebuildfileisnomoreself-contained.@libtotheresque!
Theusageissimple:
@liblib_namea(){echoHello$1}@goalhello_world@use_liblib_nameaWorldForsimplicitycanomitname:
@liba(){echoHello$1}@goalhello_world@use_libaWorldOperationally@use_libisjustsubstitutedbycontentofacorresponding@lib'sbody,asiftheabovegoalisdeclaredlike:
@goalhello_worlda(){echoHello$1}aWorld@use_libOnlyvalid:inside@goal.
Onlysingle@use_libpergoalisallowed.
NamingrulesIt'srecommendedthatyounameyourgoalsusingalphanumericchars+underscore.
However,it'spossibletonameagoalanywayyouwantprovidedthatyouapplyproperescaping:
@goal'namewithspaces'#allcharsbetween''haveliteralmeaning,sameasinshell,'itselfisnotallowedinit@goal$'namethatcontains\'singlequote'#ifyouneedtohave'inastring,usedollar-stringsandescapeit@goalusual_nameNow./makesure-lgives:
Availablegoals:'namewithspaces'$'namethatcontains\'singlequote'usual_nameNote,howgoalnamesarealreadyescapedinoutput.Thisistomakeiteasierforyoutocallitdirectly:
./makesure$'namethatcontains\'singlequote'Samenamingrulesapplytootherdirectives(like@doc).
Usuallyyouwon'tneedthisescapingtricksoften,buttheycanbeespeciallyinusefor@globgoalsiftherelevantfileshavespacesinthem:
@goal@glob'filewithspaces*.txt'Moreinfoonthistopiciscoveredintheissue.
DesignprinciplesConventionoverconfiguration.Minimalistic.Bareminimumoffeaturesthatcomposegoodwitheachother.Thereshouldbeonewaytodothething.OverallZenofPython.Thinkhardbeforeaddingnewfeature.Thinkofadamageitcouldcauseusedimproperly.Thinkofcognitivecomplexityitintroduces.Onlyaddafeaturegenericenoughtocoverlotsofusefulcasesinsteadofjustsomecornercases.Let'sbetterhavealistofrecipesforthelatter.Donotintroduceunjustifiedcomplexity.Usershouldnotbeforcedtolearnawholenewprogramminglanguagetoworkwithatool.Instead,thetoolisbasedonlimitedsetofsimpleconcepts,likegoals+dependencies+handfulofdirectives+familiarshelllanguage(bash/sh).Worseisbetter.Principleofleastsurprise.Testscoverageisamust.OmittedfeaturesGoalswithparameters,likeinjustWedeliberatelydon'tsupportthisfeature.Theideaisthatthebuildfileshouldbeself-contained,sohavealltheinformationtoruninit,noexternalparametersshouldberequired.Thisshouldbemucheasierforthefinalusertorunabuild.Theotherreasonisthattheideaofgoalparameterizationdoesn'tplaywellwithdependencies.Thetoolhoweverhaslimitedparameterizationcapabilitiesvia./makesure-DVAR=value.IncludesThisisaconsiderablecomplicationtothetool.Also,itmakesthebuildfilenotself-contained.Shellsotherthanbash/shLessportablebuild.Ifyouneedtouse,say,pythonforagoalbody,it'sunclearwhyyouevenneedmakesureatall.Besides,youalwayscanjustusepython-c"script".Customownprogramminglanguage,likemakehasWethinkthatthiswouldbeunjustifiedcomplexity.Webelievethatthepowerofshellisenough.parallelexecutionmakesureisataskrunner,notafull-fledgedbuildtool,likemake,ninjaorbazel.Soifyouneedone,justuseaproperbuildtoolofyourchoice.DevelopernotesFindsomecontributorinstructionsinDEVELOPER.md.
Similartoolsjusthttps://github.com/casey/justjustisahandywaytosaveandrunproject-specificcommandsTaskfilehttps://github.com/adriancooney/TaskfileATaskfileisabash[...]scriptthatfollowsaspecificformat[...],sitsintherootofyourproject[...]andcontainsthetaskstobuildyourproject.Taskhttps://github.com/go-task/taskTaskisataskrunner/buildtoolthataimstobesimplerandeasiertousethan,forexample,GNUMake.hakuhttps://github.com/VladimirMarkelov/hakuAtask/commandrunnerinspiredby'make'guphttps://github.com/timbertson/gupGupisageneralpurpose,recursive,topdownsoftwarebuildsystem.redohttps://github.com/apenwarr/redoredo-arecursivebuildsystem.Smaller,easier,morepowerful,andmorereliablethanmake.Tuphttps://github.com/gittup/tupTupisafile-basedbuildsystemforLinux,OSX,andWindows.Pleasehttps://github.com/thought-machine/pleasePleaseisacross-languagebuildsystemwithanemphasisonhighperformance,extensibilityandreproducibility.
评论