__pycache__/__init__.cpython-39.opt-1.pyc000064400000000674151114232410014104 0ustar00a "e@sLddlmZddlmZddlmZddlmZddlm Z eeee gZ dS))absolute_import)Query)Package) Application)ProcessN) Z __future__rZ tracer.queryrZtracer.resources.packagerZtracer.resources.applicationsrZtracer.resources.processesr__all__rr3/usr/lib/python3.9/site-packages/tracer/__init__.pys     __pycache__/__init__.cpython-39.pyc000064400000000674151114232410013145 0ustar00a "e@sLddlmZddlmZddlmZddlmZddlm Z eeee gZ dS))absolute_import)Query)Package) Application)ProcessN) Z __future__rZ tracer.queryrZtracer.resources.packagerZtracer.resources.applicationsrZtracer.resources.processesr__all__rr3/usr/lib/python3.9/site-packages/tracer/__init__.pys     __pycache__/hooks.cpython-39.opt-1.pyc000064400000003776151114232410013476 0ustar00a "e;@sHddlZddlmZddlmZiZGdddeZddZdd Z dS) N) HOOKS_DIRS) load_sourcec@s eZdZdZddZddZdS) HooksObserverz Provides interface for calling user hooks When initializing, loads all hooks located in HOOKS_DIRS. Then it can called with application name as argument. Observer ensures calling all hooks defined for the application. cCs tdSN)_register_hooks)selfr0/usr/lib/python3.9/site-packages/tracer/hooks.py__init__!szHooksObserver.__init__cCs"|tvr dSddt|DdS)NcSsg|] }|qSrr).0frrr (z*HooksObserver.__call__..)_hooks)rapprrr __call__$szHooksObserver.__call__N)__name__ __module__ __qualname____doc__r rrrrr rsrcsfdd}|S)a Decorator for tracer hooks. Example:: from tracer import hooks @hooks.match("foo") def hook_app(): print("Hey, application foo was found") .. note:: You can match multiple applications by calling ``@hooks.match`` with list of them. cs>ttkrngD]"}|tvr*gt|<t||q|Sr)typelistrappend)r rappsrr decorator;s zmatch..decoratorr)rrrrr match+s rc CsntD]d}t|D]T\}}}|D]D}tj|d}zt|tj||Wq tybYq Yq 0q qqdS)Nr)roswalkpathsplitextrjoin Exception)Zhook_dirrootdirsfilesfnamemodnamerrr rDs r) rZ tracer.pathsrZtracer.resources.pycomprrobjectrrrrrrr s   __pycache__/hooks.cpython-39.pyc000064400000003776151114232410012537 0ustar00a "e;@sHddlZddlmZddlmZiZGdddeZddZdd Z dS) N) HOOKS_DIRS) load_sourcec@s eZdZdZddZddZdS) HooksObserverz Provides interface for calling user hooks When initializing, loads all hooks located in HOOKS_DIRS. Then it can called with application name as argument. Observer ensures calling all hooks defined for the application. cCs tdSN)_register_hooks)selfr0/usr/lib/python3.9/site-packages/tracer/hooks.py__init__!szHooksObserver.__init__cCs"|tvr dSddt|DdS)NcSsg|] }|qSrr).0frrr (z*HooksObserver.__call__..)_hooks)rapprrr __call__$szHooksObserver.__call__N)__name__ __module__ __qualname____doc__r rrrrr rsrcsfdd}|S)a Decorator for tracer hooks. Example:: from tracer import hooks @hooks.match("foo") def hook_app(): print("Hey, application foo was found") .. note:: You can match multiple applications by calling ``@hooks.match`` with list of them. cs>ttkrngD]"}|tvr*gt|<t||q|Sr)typelistrappend)r rappsrr decorator;s zmatch..decoratorr)rrrrr match+s rc CsntD]d}t|D]T\}}}|D]D}tj|d}zt|tj||Wq tybYq Yq 0q qqdS)Nr)roswalkpathsplitextrjoin Exception)Zhook_dirrootdirsfilesfnamemodnamerrr rDs r) rZ tracer.pathsrZtracer.resources.pycomprrobjectrrrrrrr s   __pycache__/main.cpython-39.opt-1.pyc000064400000002562151114232410013267 0ustar00a "e@s|ddlmZddlZddlZddlZddlmZddlmZddl m Z ddl m Z m Z mZmZmZddlmZdd ZdS) )print_functionN)Router)parser)Package) TracerErrorUnsupportedDistribution PathNotFoundLockedDatabaseDatabasePermissions)_c CsJt}g}tjs.dtjvr.tj}g}|j |j |D]"}| t ||j r\tndqBzt||}|WStttfy}z|tdWYd}~nd}~0ty}z(|ttdtdWYd}~n\d}~0ty&}z|tdWYd}~n(d}~0ttfyDtdYn0dS)NZSSH_CONNECTIONz,You will probably need to run tracer as root)r parse_argssysstdinisattyosenvironreadlinesplitpackagesZpkgsappendrZnowtimerdispatchrrr printexitr r rKeyboardInterruptEOFError)argsZstdin_packagesrpackageZrouterexr!//usr/lib/python3.9/site-packages/tracer/main.pyrun%s,    r#)Z __future__rrrrZtracer.resources.routerrZtracer.resources.args_parserrZtracer.resources.packagerZtracer.resources.exceptionsrrrr r Ztracer.resources.langr r#r!r!r!r"s     __pycache__/main.cpython-39.pyc000064400000002562151114232410012330 0ustar00a "e@s|ddlmZddlZddlZddlZddlmZddlmZddl m Z ddl m Z m Z mZmZmZddlmZdd ZdS) )print_functionN)Router)parser)Package) TracerErrorUnsupportedDistribution PathNotFoundLockedDatabaseDatabasePermissions)_c CsJt}g}tjs.dtjvr.tj}g}|j |j |D]"}| t ||j r\tndqBzt||}|WStttfy}z|tdWYd}~nd}~0ty}z(|ttdtdWYd}~n\d}~0ty&}z|tdWYd}~n(d}~0ttfyDtdYn0dS)NZSSH_CONNECTIONz,You will probably need to run tracer as root)r parse_argssysstdinisattyosenvironreadlinesplitpackagesZpkgsappendrZnowtimerdispatchrrr printexitr r rKeyboardInterruptEOFError)argsZstdin_packagesrpackageZrouterexr!//usr/lib/python3.9/site-packages/tracer/main.pyrun%s,    r#)Z __future__rrrrZtracer.resources.routerrZtracer.resources.args_parserrZtracer.resources.packagerZtracer.resources.exceptionsrrrr r Ztracer.resources.langr r#r!r!r!r"s     __pycache__/paths.cpython-39.opt-1.pyc000064400000001545151114232410013462 0ustar00a "e=@sddlZddlmZmZmZddlmZddZeeeeZ ee dddgZ d gZ d gZ ee d d d gZ z8eZe edede ededWneyYn0dS)N)dirnamerealpath expanduser)SystemcCs&|D]}tj|r|Sq|dS)Nr)ospathisdir)pathsrr 0/usr/lib/python3.9/site-packages/tracer/paths.py__s  r /dataz/usr/share/tracerz /etc/tracerz/etc/tracer/hooksz/build/localez/usr/share/locale~z/.config/tracerz/.config/tracer/hooks)rZos.pathrrrZtracer.resources.systemrr __file__Z PROJECT_DIRZDATA_DIRZUSER_CONFIG_DIRSZ HOOKS_DIRSZLANG_DIRuserappendOSErrorr r r r s,    __pycache__/paths.cpython-39.pyc000064400000001545151114232410012523 0ustar00a "e=@sddlZddlmZmZmZddlmZddZeeeeZ ee dddgZ d gZ d gZ ee d d d gZ z8eZe edede ededWneyYn0dS)N)dirnamerealpath expanduser)SystemcCs&|D]}tj|r|Sq|dS)Nr)ospathisdir)pathsrr 0/usr/lib/python3.9/site-packages/tracer/paths.py__s  r /dataz/usr/share/tracerz /etc/tracerz/etc/tracer/hooksz/build/localez/usr/share/locale~z/.config/tracerz/.config/tracer/hooks)rZos.pathrrrZtracer.resources.systemrr __file__Z PROJECT_DIRZDATA_DIRZUSER_CONFIG_DIRSZ HOOKS_DIRSZLANG_DIRuserappendOSErrorr r r r s,    __pycache__/query.cpython-39.opt-1.pyc000064400000004346151114232410013512 0ustar00a "e@s`ddlmZddlmZddlmZddlmZddlm Z Gddde Z Gdd d e Z d S) )Tracer)System)Rules) Applications) dump_memoryc@s6eZdZdZefddZddZddZd d d ZdS) QueryaE Provide API for Tracer querying operations. They are executed kind of lazily, so running the operation will return just an wrapper class with ``get()`` method. Example:: from tracer.query import Query q = Query() q.affected_applications().get() .. note:: Some querying methods can require root permissions cCs|tttt|_dSN)rZpackage_managerrrr_tracer)selfZtracerr 0/usr/lib/python3.9/site-packages/tracer/query.py__init__+szQuery.__init__cCs ||j_|S)z.List of ``Package`` that only should be traced)r Zspecified_packages)r Zpackagesr r r from_packages.szQuery.from_packagescCs d|j_|S)z Pretend that specified packages have been updated just now. Benefit of this is absolutely no need for openning the package history database T)r nowr r r r r3sz Query.nowNcCst|jjd|iS)z? Return list of applications which use some outdated files user)Lazyr Ztrace_affected)r rr r r affected_applications;szQuery.affected_applications)N) __name__ __module__ __qualname____doc__rr rrrr r r r rs  rc@seZdZddZddZdS)rcCs||_||_dSr_method_kwargs)r methodkwargsr r r r Csz Lazy.__init__cCs|jfi|jSrrrr r r getGszLazy.getN)rrrr rr r r r rBsrN) Ztracer.resources.tracerrZtracer.resources.systemrZtracer.resources.rulesrZtracer.resources.applicationsrZtracer.resources.memoryrobjectrrr r r r s     (__pycache__/query.cpython-39.pyc000064400000004346151114232410012553 0ustar00a "e@s`ddlmZddlmZddlmZddlmZddlm Z Gddde Z Gdd d e Z d S) )Tracer)System)Rules) Applications) dump_memoryc@s6eZdZdZefddZddZddZd d d ZdS) QueryaE Provide API for Tracer querying operations. They are executed kind of lazily, so running the operation will return just an wrapper class with ``get()`` method. Example:: from tracer.query import Query q = Query() q.affected_applications().get() .. note:: Some querying methods can require root permissions cCs|tttt|_dSN)rZpackage_managerrrr_tracer)selfZtracerr 0/usr/lib/python3.9/site-packages/tracer/query.py__init__+szQuery.__init__cCs ||j_|S)z.List of ``Package`` that only should be traced)r Zspecified_packages)r Zpackagesr r r from_packages.szQuery.from_packagescCs d|j_|S)z Pretend that specified packages have been updated just now. Benefit of this is absolutely no need for openning the package history database T)r nowr r r r r3sz Query.nowNcCst|jjd|iS)z? Return list of applications which use some outdated files user)Lazyr Ztrace_affected)r rr r r affected_applications;szQuery.affected_applications)N) __name__ __module__ __qualname____doc__rr rrrr r r r rs  rc@seZdZddZddZdS)rcCs||_||_dSr_method_kwargs)r methodkwargsr r r r Csz Lazy.__init__cCs|jfi|jSrrrr r r getGszLazy.getN)rrrr rr r r r rBsrN) Ztracer.resources.tracerrZtracer.resources.systemrZtracer.resources.rulesrZtracer.resources.applicationsrZtracer.resources.memoryrobjectrrr r r r s     (__pycache__/version.cpython-39.opt-1.pyc000064400000000266151114232410014027 0ustar00a "ey@s dZdZdS)z1.11N) __version__Z __release__rr2/usr/lib/python3.9/site-packages/tracer/version.pys__pycache__/version.cpython-39.pyc000064400000000266151114232410013070 0ustar00a "ey@s dZdZdS)z1.11N) __version__Z __release__rr2/usr/lib/python3.9/site-packages/tracer/version.pyscontrollers/__pycache__/__init__.cpython-39.opt-1.pyc000064400000000232151114232410016440 0ustar00a "e@sdS)Nrrr?/usr/lib/python3.9/site-packages/tracer/controllers/__init__.pycontrollers/__pycache__/__init__.cpython-39.pyc000064400000000232151114232410015501 0ustar00a "e@sdS)Nrrr?/usr/lib/python3.9/site-packages/tracer/controllers/__init__.pycontrollers/__pycache__/default.cpython-39.opt-1.pyc000064400000011113151114232410016325 0ustar00a "e@sddlZddlZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZdd lmZdd lmZdd lmZzeZWneyYn0Gd ddeZdS)N) HooksObserver) DefaultView)InteractiveView)NoteForHiddenView)_)Tracer)System) dump_memory) Applications)Rules)HelperControllerc@sXeZdZdZdZdZddZddZddZdd Z d d Z d d Z ddZ ddZ dS)DefaultControllerNcCs||_ttj|jdtttt|jd|_ |j |j _ |j d|j _ |rN||j _ |j ||j|_|jjr|jtjdg|_dS)N)erased)ZmemoryZhooks_observerrrDAEMON)argsrrZpackage_managerrr r r rtracerZnowZ timestampZspecified_packagesZtrace_affected_useruser applicationsZ daemons_onlyZ filter_typesTYPES)selfrZpackagesr>/usr/lib/python3.9/site-packages/tracer/controllers/default.py__init__/s   zDefaultController.__init__cCsJ|jjs:t}|d|j|d|j||t|dS)Nrr) rZ hooks_onlyrassignrrendercreate_reboot_required_fileexit status_code)rviewrrrrBszDefaultController.rendercCst|j}||j|jD]}|||jtdqt}|d|j|dt|j|d|j t j d|d|j t j d| dS)Nr total_count session_countSESSION static_countSTATIC) r r_restartable_applicationsr print_helperprintrrlen count_typer rr)rhelper_controllerZ applicationrrrrrender_helpersKs  z DefaultController.render_helpersc Cs`t|j}||j|jd}t}|d||d|j|dt|j|d|jt j d|d|jt j d| | d| d| dkrq\t d td td }zL|d krWdSt|d kst|t|krt||t|d|jWn&tttfy:t tdYn0tjdtddtq dS)Nnamerrr!r"r#r$r% z0Press application number for help or 'q' to quitz--> qrzWrong application numberz -- z)Press to get list of applicationsz --)r rr&rsortedrrr)r*r rrgetr(rinputint IndexErrorr' SyntaxError ValueErrorsysstdoutwrite)rr+ZfilteredrZanswerrrrrender_interactiveXs*   z$DefaultController.render_interactivecCs\d}t|jdkrd}|jtjdr,d}|jtjdrBd}|jtjdrXd}|S) z 0 - No affected applications 101 - Found some affected applications 102 - Found some affected daemons 103 - Session restart needed 104 - Reboot needed rerfr#gr%h)r)rr*r r)rcoderrrrvszDefaultController.status_codecCsJ|jtjdrFtdd}|dWdn1s<0YdS)zm If a reboot is needed, create a /run/reboot-required file. This is how Debian/Ubuntu distros does it. r%z/run/reboot-requiredwzTracer says reboot is required N)rr*r ropenr:)rfprrrrs z-DefaultController.create_reboot_required_filecCs$|js |tjdtjdgS|S)Nr%r#)allZ exclude_typesr r)rrrrrrr&sz+DefaultController._restartable_applicationscCs:|dgks|dkrdS|dkr"|S|s.tS|dSdS)N*rootr)rr)rrrrrrs  zDefaultController._user)__name__ __module__ __qualname__rrZ processesrrr,r;rrr&rrrrrr )s   r )osr8Z tracer.hooksrZtracer.views.defaultrZtracer.views.interactiverZtracer.views.note_for_hiddenrZtracer.resources.langrZtracer.resources.tracerrZtracer.resources.systemrZtracer.resources.memoryr Ztracer.resources.applicationsr Ztracer.resources.rulesr Ztracer.controllers.helperr Z raw_inputr3 NameErrorobjectr rrrrs"            controllers/__pycache__/default.cpython-39.pyc000064400000011113151114232410015366 0ustar00a "e@sddlZddlZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZdd lmZdd lmZdd lmZzeZWneyYn0Gd ddeZdS)N) HooksObserver) DefaultView)InteractiveView)NoteForHiddenView)_)Tracer)System) dump_memory) Applications)Rules)HelperControllerc@sXeZdZdZdZdZddZddZddZdd Z d d Z d d Z ddZ ddZ dS)DefaultControllerNcCs||_ttj|jdtttt|jd|_ |j |j _ |j d|j _ |rN||j _ |j ||j|_|jjr|jtjdg|_dS)N)erased)ZmemoryZhooks_observerrrDAEMON)argsrrZpackage_managerrr r r rtracerZnowZ timestampZspecified_packagesZtrace_affected_useruser applicationsZ daemons_onlyZ filter_typesTYPES)selfrZpackagesr>/usr/lib/python3.9/site-packages/tracer/controllers/default.py__init__/s   zDefaultController.__init__cCsJ|jjs:t}|d|j|d|j||t|dS)Nrr) rZ hooks_onlyrassignrrendercreate_reboot_required_fileexit status_code)rviewrrrrBszDefaultController.rendercCst|j}||j|jD]}|||jtdqt}|d|j|dt|j|d|j t j d|d|j t j d| dS)Nr total_count session_countSESSION static_countSTATIC) r r_restartable_applicationsr print_helperprintrrlen count_typer rr)rhelper_controllerZ applicationrrrrrender_helpersKs  z DefaultController.render_helpersc Cs`t|j}||j|jd}t}|d||d|j|dt|j|d|jt j d|d|jt j d| | d| d| dkrq\t d td td }zL|d krWdSt|d kst|t|krt||t|d|jWn&tttfy:t tdYn0tjdtddtq dS)Nnamerrr!r"r#r$r% z0Press application number for help or 'q' to quitz--> qrzWrong application numberz -- z)Press to get list of applicationsz --)r rr&rsortedrrr)r*r rrgetr(rinputint IndexErrorr' SyntaxError ValueErrorsysstdoutwrite)rr+ZfilteredrZanswerrrrrender_interactiveXs*   z$DefaultController.render_interactivecCs\d}t|jdkrd}|jtjdr,d}|jtjdrBd}|jtjdrXd}|S) z 0 - No affected applications 101 - Found some affected applications 102 - Found some affected daemons 103 - Session restart needed 104 - Reboot needed rerfr#gr%h)r)rr*r r)rcoderrrrvszDefaultController.status_codecCsJ|jtjdrFtdd}|dWdn1s<0YdS)zm If a reboot is needed, create a /run/reboot-required file. This is how Debian/Ubuntu distros does it. r%z/run/reboot-requiredwzTracer says reboot is required N)rr*r ropenr:)rfprrrrs z-DefaultController.create_reboot_required_filecCs$|js |tjdtjdgS|S)Nr%r#)allZ exclude_typesr r)rrrrrrr&sz+DefaultController._restartable_applicationscCs:|dgks|dkrdS|dkr"|S|s.tS|dSdS)N*rootr)rr)rrrrrrs  zDefaultController._user)__name__ __module__ __qualname__rrZ processesrrr,r;rrr&rrrrrr )s   r )osr8Z tracer.hooksrZtracer.views.defaultrZtracer.views.interactiverZtracer.views.note_for_hiddenrZtracer.resources.langrZtracer.resources.tracerrZtracer.resources.systemrZtracer.resources.memoryr Ztracer.resources.applicationsr Ztracer.resources.rulesr Ztracer.controllers.helperr Z raw_inputr3 NameErrorobjectr rrrrs"            controllers/__pycache__/helper.cpython-39.opt-1.pyc000064400000004454151114232410016172 0ustar00a "e @stddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZGd d d eZd S) ) AccessDenied)System) dump_memory) HelperView)_)Tracer) Applications)Rulesc@s6eZdZdZdZd ddZddZddZdd ZdS) HelperControllerNcCs||_||_dS)N)argspackages)selfr r r=/usr/lib/python3.9/site-packages/tracer/controllers/helper.py__init__#szHelperController.__init__cCs>|jjD]0}|t||j||jjdkrtdqdS)N)r helper print_helperrfindprint)r Zapp_namerrrrender's zHelperController.renderc Cs|jrt}||}|r*|ttttt}|jj |_ |j rR|j |_ z| |}Wnt yztd}Yn0|||}t}|d||d|j|d||d||d||d||nttd|jdS) Nz!You don't have enough permissionsr Z processesZ applicationpackage affected_byaffectsz%Application called {0} is not running) instancesrZpackage_managerZ provided_byZ load_inforr rr Znowr Zspecified_packagesZtrace_applicationrr_affectsrZassignrrformatname) r appr Zmanagerrtrrrviewrrrr-s*         zHelperController.print_helpercCs>|sdS|d}||jkr"dS|dd|jDvr:dS|S)NrcSsg|]}|qSr)parentr).0prrr Pz-HelperController._affects..)rr)r rrZlastrrrrHs  zHelperController._affects)N) __name__ __module__ __qualname__r r rrrrrrrrr s  r N)ZpsutilrZtracer.resources.systemrZtracer.resources.memoryrZtracer.views.helperrZtracer.resources.langrZtracer.resources.tracerrZtracer.resources.applicationsrZtracer.resources.rulesr objectr rrrrs        controllers/__pycache__/helper.cpython-39.pyc000064400000004454151114232410015233 0ustar00a "e @stddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZGd d d eZd S) ) AccessDenied)System) dump_memory) HelperView)_)Tracer) Applications)Rulesc@s6eZdZdZdZd ddZddZddZdd ZdS) HelperControllerNcCs||_||_dS)N)argspackages)selfr r r=/usr/lib/python3.9/site-packages/tracer/controllers/helper.py__init__#szHelperController.__init__cCs>|jjD]0}|t||j||jjdkrtdqdS)N)r helper print_helperrfindprint)r Zapp_namerrrrender's zHelperController.renderc Cs|jrt}||}|r*|ttttt}|jj |_ |j rR|j |_ z| |}Wnt yztd}Yn0|||}t}|d||d|j|d||d||d||d||nttd|jdS) Nz!You don't have enough permissionsr Z processesZ applicationpackage affected_byaffectsz%Application called {0} is not running) instancesrZpackage_managerZ provided_byZ load_inforr rr Znowr Zspecified_packagesZtrace_applicationrr_affectsrZassignrrformatname) r appr Zmanagerrtrrrviewrrrr-s*         zHelperController.print_helpercCs>|sdS|d}||jkr"dS|dd|jDvr:dS|S)NrcSsg|]}|qSr)parentr).0prrr Pz-HelperController._affects..)rr)r rrZlastrrrrHs  zHelperController._affects)N) __name__ __module__ __qualname__r r rrrrrrrrr s  r N)ZpsutilrZtracer.resources.systemrZtracer.resources.memoryrZtracer.views.helperrZtracer.resources.langrZtracer.resources.tracerrZtracer.resources.applicationsrZtracer.resources.rulesr objectr rrrrs        controllers/__pycache__/resource.cpython-39.opt-1.pyc000064400000006750151114232410016543 0ustar00a "e @sddlmZddlZddlZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd lmZdd lmZGdddeZdS))absolute_importN)datetime) Processes)System)Rules) Applications) __version__) ProcessesView) PackagesView) RulesView)ApplicationsView) SystemViewc@sHeZdZdZddZddZddZdd Zd d Zd d Z ddZ dS)ResourceControllerNcCs ||_dS)N)args)selfrr?/usr/lib/python3.9/site-packages/tracer/controllers/resource.py__init__*szResourceController.__init__cCsh|jjd}|dkr|nF|dkr0|n4|dkrB|n"|dkrT|n|dkrd|dS)Nr processespackagesrules applicationssystem)rresourcerender_processesrender_packages render_rulesrender_applications render_system)rrrrrrender-s  zResourceController.rendercCs"t}|dt|dS)Nr)r assignrallr rviewrrrr5sz#ResourceController.render_processescCs`|jjdr|jjdnt}t}||}t}|d||dt|dS)Nrr boot_time) r timestamprr%package_managerZpackages_newer_thanr r!r )rr&Zmanagerrr$rrrr:s   z"ResourceController.render_packagescCs"t}|dt|dS)Nr)r r!rr"r r#rrrrDszResourceController.render_rulescCs"t}|dt|dS)Nr)r r!rr"r r#rrrrIsz&ResourceController.render_applicationscCs"ttt}t|dd}ztddt D}Wn(t yjtddt D}Yn0t }t}|dt|dt|d||d t|d ||d t|d ||d t|dtt|dtt|dS)N.rcSsg|] }|jqSrname.0userrrr Sz4ResourceController.render_system..cSsg|] }|jqSrr)r+rrrr.Ur/Zpython distributionpackage_managersinituptimer-usersversionZ rules_countZapplications_count)rZnowZ fromtimestamprr%strsplitsetpsutilZ get_usersAttributeErrorr4r'namesr r!Zpython_versionr0Z init_systemr-rlenrr"rr )rr3r4r1r$rrrrNs&      z ResourceController.render_system) __name__ __module__ __qualname__rrr rrrrrrrrrr&s r)Z __future__rosr9rZtracer.resources.processesrZtracer.resources.systemrZtracer.resources.rulesrZtracer.resources.applicationsrZtracer.versionrZtracer.views.resource.processesr Ztracer.views.resource.packagesr Ztracer.views.resource.rulesr Z"tracer.views.resource.applicationsr Ztracer.views.resource.systemr objectrrrrrs            controllers/__pycache__/resource.cpython-39.pyc000064400000006750151114232410015604 0ustar00a "e @sddlmZddlZddlZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd lmZdd lmZGdddeZdS))absolute_importN)datetime) Processes)System)Rules) Applications) __version__) ProcessesView) PackagesView) RulesView)ApplicationsView) SystemViewc@sHeZdZdZddZddZddZdd Zd d Zd d Z ddZ dS)ResourceControllerNcCs ||_dS)N)args)selfrr?/usr/lib/python3.9/site-packages/tracer/controllers/resource.py__init__*szResourceController.__init__cCsh|jjd}|dkr|nF|dkr0|n4|dkrB|n"|dkrT|n|dkrd|dS)Nr processespackagesrules applicationssystem)rresourcerender_processesrender_packages render_rulesrender_applications render_system)rrrrrrender-s  zResourceController.rendercCs"t}|dt|dS)Nr)r assignrallr rviewrrrr5sz#ResourceController.render_processescCs`|jjdr|jjdnt}t}||}t}|d||dt|dS)Nrr boot_time) r timestamprr%package_managerZpackages_newer_thanr r!r )rr&Zmanagerrr$rrrr:s   z"ResourceController.render_packagescCs"t}|dt|dS)Nr)r r!rr"r r#rrrrDszResourceController.render_rulescCs"t}|dt|dS)Nr)r r!rr"r r#rrrrIsz&ResourceController.render_applicationscCs"ttt}t|dd}ztddt D}Wn(t yjtddt D}Yn0t }t}|dt|dt|d||d t|d ||d t|d ||d t|dtt|dtt|dS)N.rcSsg|] }|jqSrname.0userrrr Sz4ResourceController.render_system..cSsg|] }|jqSrr)r+rrrr.Ur/Zpython distributionpackage_managersinituptimer-usersversionZ rules_countZapplications_count)rZnowZ fromtimestamprr%strsplitsetpsutilZ get_usersAttributeErrorr4r'namesr r!Zpython_versionr0Z init_systemr-rlenrr"rr )rr3r4r1r$rrrrNs&      z ResourceController.render_system) __name__ __module__ __qualname__rrr rrrrrrrrrr&s r)Z __future__rosr9rZtracer.resources.processesrZtracer.resources.systemrZtracer.resources.rulesrZtracer.resources.applicationsrZtracer.versionrZtracer.views.resource.processesr Ztracer.views.resource.packagesr Ztracer.views.resource.rulesr Z"tracer.views.resource.applicationsr Ztracer.views.resource.systemr objectrrrrrs            controllers/__init__.py000064400000000000151114232410011203 0ustar00controllers/default.py000064400000012236151114232410011106 0ustar00#-*- coding: utf-8 -*- # default.py # Defines DefaultController # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # import os import sys from tracer.hooks import HooksObserver from tracer.views.default import DefaultView from tracer.views.interactive import InteractiveView from tracer.views.note_for_hidden import NoteForHiddenView from tracer.resources.lang import _ from tracer.resources.tracer import Tracer from tracer.resources.system import System from tracer.resources.memory import dump_memory from tracer.resources.applications import Applications from tracer.resources.rules import Rules from tracer.controllers.helper import HelperController # compatibility with Py2 and Py3 - rename raw_input() to input() on Py2 try: input = raw_input except NameError: pass class DefaultController(object): args = None tracer = None processes = None def __init__(self, args, packages): self.args = args self.tracer = Tracer( System.package_manager(erased=args.erased), Rules, Applications, memory=dump_memory, hooks_observer=HooksObserver(), erased=args.erased ) self.tracer.now = args.now self.tracer.timestamp = args.timestamp[0] if packages: self.tracer.specified_packages = packages self.applications = self.tracer.trace_affected(self._user(args.user)) if self.args.daemons_only: self.applications = self.applications.filter_types([Applications.TYPES["DAEMON"]]) def render(self): if not self.args.hooks_only: view = DefaultView() view.assign("applications", self.applications) view.assign("args", self.args) view.render() self.create_reboot_required_file() exit(self.status_code()) def render_helpers(self): helper_controller = HelperController(self.args) for application in self._restartable_applications(self.applications, self.args): helper_controller.print_helper(application, self.args) print("") view = NoteForHiddenView() view.assign("args", self.args) view.assign("total_count", len(self.applications)) view.assign("session_count", self.applications.count_type(Applications.TYPES['SESSION'])) view.assign("static_count", self.applications.count_type(Applications.TYPES['STATIC'])) view.render() def render_interactive(self): helper_controller = HelperController(self.args) filtered = self._restartable_applications(self.applications, self.args).sorted("name") while True: view = InteractiveView() view.assign("applications", filtered) view.assign("args", self.args) view.assign("total_count", len(self.applications)) view.assign("session_count", self.applications.count_type(Applications.TYPES['SESSION'])) view.assign("static_count", self.applications.count_type(Applications.TYPES['STATIC'])) view.render() # If there are only hidden applications (any listed) if view.get("total_count") == view.get("session_count") + view.get("static_count"): break print("\n" + _("Press application number for help or 'q' to quit")) answer = input("--> ") try: if answer == "q": return elif int(answer) <= 0 or int(answer) > len(filtered): raise IndexError helper_controller.print_helper(filtered[int(answer) - 1], self.args) except (SyntaxError, IndexError, ValueError): print(_("Wrong application number")) sys.stdout.write("\n-- " + _("Press to get list of applications") + " --") input() def status_code(self): """ 0 - No affected applications 101 - Found some affected applications 102 - Found some affected daemons 103 - Session restart needed 104 - Reboot needed """ code = 0 if len(self.applications) > 0: code = 101 if self.applications.count_type(Applications.TYPES['DAEMON']): code = 102 if self.applications.count_type(Applications.TYPES['SESSION']): code = 103 if self.applications.count_type(Applications.TYPES['STATIC']): code = 104 return code def create_reboot_required_file(self): """ If a reboot is needed, create a /run/reboot-required file. This is how Debian/Ubuntu distros does it. """ if self.applications.count_type(Applications.TYPES["STATIC"]): with open("/run/reboot-required", "w") as fp: fp.write("Tracer says reboot is required\n") def _restartable_applications(self, applications, args): return applications.exclude_types([ Applications.TYPES['STATIC'], Applications.TYPES['SESSION'] ]) if not args.all else applications def _user(self, user): if user == ['*'] or user == '*': return None elif user == 'root': return user elif not user: return System.user() else: return user[0] controllers/helper.py000064400000005006151114232410010736 0ustar00#-*- coding: utf-8 -*- # helper.py # Defines HelperController # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from psutil import AccessDenied from tracer.resources.system import System from tracer.resources.memory import dump_memory from tracer.views.helper import HelperView from tracer.resources.lang import _ from tracer.resources.tracer import Tracer from tracer.resources.applications import Applications from tracer.resources.rules import Rules class HelperController(object): args = None packages = None def __init__(self, args, packages=None): self.args = args self.packages = packages def render(self): for app_name in self.args.helper: self.print_helper(Applications.find(app_name), self.args) if app_name != self.args.helper[-1]: print("") def print_helper(self, app, args): if app.instances: manager = System.package_manager() package = manager.provided_by(app) if package: package.load_info(System.package_manager()) tr = Tracer(System.package_manager(), Rules, Applications) tr.now = self.args.now if self.packages: tr.specified_packages = self.packages try: affected_by = tr.trace_application(app) except AccessDenied: affected_by = _("You don't have enough permissions") affects = self._affects(app, affected_by) view = HelperView() view.assign("args", args) view.assign("processes", app.instances) view.assign("application", app) view.assign("package", package) view.assign("affected_by", affected_by) view.assign("affects", affects) view.render() else: print(_("Application called {0} is not running").format(app.name)) def _affects(self, app, affected_by): if not affected_by: return None last = affected_by[-1].name() if last == app.name: return None if last not in [p.parent().name() for p in app.instances]: return None return last controllers/resource.py000064400000006340151114232410011310 0ustar00#-*- coding: utf-8 -*- # resource.py # Defines ResourceController # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import import os import psutil from datetime import datetime from tracer.resources.processes import Processes from tracer.resources.system import System from tracer.resources.rules import Rules from tracer.resources.applications import Applications from tracer.version import __version__ from tracer.views.resource.processes import ProcessesView from tracer.views.resource.packages import PackagesView from tracer.views.resource.rules import RulesView from tracer.views.resource.applications import ApplicationsView from tracer.views.resource.system import SystemView class ResourceController(object): args = None def __init__(self, args): self.args = args def render(self): r = self.args.resource[0] if r == 'processes': self.render_processes() elif r == 'packages': self.render_packages() elif r == 'rules': self.render_rules() elif r == 'applications': self.render_applications() elif r == 'system': self.render_system() def render_processes(self): view = ProcessesView() view.assign('processes', Processes.all()) view.render() def render_packages(self): timestamp = self.args.timestamp[0] if self.args.timestamp[0] else System.boot_time() manager = System.package_manager() packages = manager.packages_newer_than(timestamp) view = PackagesView() view.assign('packages', packages) view.assign('boot_time', System.boot_time()) view.render() def render_rules(self): view = RulesView() view.assign('rules', Rules.all()) view.render() def render_applications(self): view = ApplicationsView() view.assign('applications', Applications.all()) view.render() def render_system(self): uptime = datetime.now() - datetime.fromtimestamp(System.boot_time()) uptime = str(uptime).split('.')[0] try: users = set([user.name for user in psutil.get_users()]) except AttributeError: users = set([user.name for user in psutil.users()]) package_managers = System.package_manager().names() view = SystemView() view.assign('python', System.python_version()) view.assign('distribution', System.distribution()) view.assign('package_managers', package_managers) view.assign('init', System.init_system()) view.assign('uptime', uptime) view.assign('user', System.user()) view.assign('users', users) view.assign('version', __version__) view.assign('rules_count', len(Rules.all())) view.assign('applications_count', len(Applications.all())) view.render() packageManagers/__pycache__/__init__.cpython-39.opt-1.pyc000064400000000236151114232410017147 0ustar00a "e@sdS)NrrrC/usr/lib/python3.9/site-packages/tracer/packageManagers/__init__.pypackageManagers/__pycache__/__init__.cpython-39.pyc000064400000000236151114232410016210 0ustar00a "e@sdS)NrrrC/usr/lib/python3.9/site-packages/tracer/packageManagers/__init__.pypackageManagers/__pycache__/alpm.cpython-39.opt-1.pyc000064400000007000151114232410016335 0ustar00a "eJ @sxddlmZddlmZedvrtddlZddlmZddlm Z ddl m Z dd l m Z ddlZGd d d eZdS) )absolute_import)System)ZarchZarcharmN)IPackageManager)Package)PackagesCollection) Applicationsc@sXeZdZddZddZddZddZd d Zd d Zd dZ e ddZ ddZ dS)AlpmcOs$||_tdd|_|j|_dS)N/z/var/lib/pacman)ZoptspyalpmZHandleZhandleZ get_localdbdb)selfargskwargsr?/usr/lib/python3.9/site-packages/tracer/packageManagers/alpm.py__init__ sz Alpm.__init__cCs6t}|jjD]"}|j|kr|t|j|jq|S)zR Returns list of packages which were modified between unix_time and present )rr pkgcache installdateappendrname)r Z unix_timeZnew_pkgspkgrrrpackages_newer_than%s   zAlpm.packages_newer_thancCs$|j|}|sgSdd|jDS)z1 Returns list of files provided by package cSsg|]}d|dqS)r rr.0frrr 8z&Alpm.package_files..)r get_pkgfiles)r pkg_namerrrr package_files0s zAlpm.package_filescCs2|sdS|j|j}|sdS|j|_|j|_dS)zN From database load informations about given package and set them to it N)r rrZdesc descriptionrZmodified)r packagerrrrload_package_info:szAlpm.load_package_infocCs|jd}||jS)z@ Returns name of package which provides given application r)Z instances_file_provided_byZexe)r ZappZprocessrrr provided_byIs zAlpm.provided_bycCs*|j|}|r&t|j|dkr&|SdS)z< Find a package by name and some other input criteria rN)r rr vercmpversion)r r r(rrrr find_packageQs zAlpm.find_packagecCst|j|jS)zX vercmp returns: < 0 if ver1 < ver2 0 if ver1 == ver2 > 0 if ver1 > ver2 )r r'r()r Zpackage1Zpackage2rrrcompare_packagesYszAlpm.compare_packagescCs0t||}|t|kr(|||kr(dSdSdS)z5 Searches a sorted list, returns True if found TFN)bisectZ bisect_leftlen)litemirrr _bsearch_listbs zAlpm._bsearch_listcCsH|jjD]:}dd|jD}|||ddrt|j|jSqdS)z9 Returns name of package which provides given file cSsg|] }|dqS)rrrrrrrsrz*Alpm._file_provided_by..rN)r rrr0rrr)r file_namerrrrrr%ms  zAlpm._file_provided_byN) __name__ __module__ __qualname__rrr!r$r&r)r* staticmethodr0r%rrrrr s    r )Z __future__rZtracer.resources.systemrZ distributionr+ZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrZtracer.resources.applicationsrr r rrrrs       packageManagers/__pycache__/alpm.cpython-39.pyc000064400000007000151114232410015376 0ustar00a "eJ @sxddlmZddlmZedvrtddlZddlmZddlm Z ddl m Z dd l m Z ddlZGd d d eZdS) )absolute_import)System)ZarchZarcharmN)IPackageManager)Package)PackagesCollection) Applicationsc@sXeZdZddZddZddZddZd d Zd d Zd dZ e ddZ ddZ dS)AlpmcOs$||_tdd|_|j|_dS)N/z/var/lib/pacman)ZoptspyalpmZHandleZhandleZ get_localdbdb)selfargskwargsr?/usr/lib/python3.9/site-packages/tracer/packageManagers/alpm.py__init__ sz Alpm.__init__cCs6t}|jjD]"}|j|kr|t|j|jq|S)zR Returns list of packages which were modified between unix_time and present )rr pkgcache installdateappendrname)r Z unix_timeZnew_pkgspkgrrrpackages_newer_than%s   zAlpm.packages_newer_thancCs$|j|}|sgSdd|jDS)z1 Returns list of files provided by package cSsg|]}d|dqS)r rr.0frrr 8z&Alpm.package_files..)r get_pkgfiles)r pkg_namerrrr package_files0s zAlpm.package_filescCs2|sdS|j|j}|sdS|j|_|j|_dS)zN From database load informations about given package and set them to it N)r rrZdesc descriptionrZmodified)r packagerrrrload_package_info:szAlpm.load_package_infocCs|jd}||jS)z@ Returns name of package which provides given application r)Z instances_file_provided_byZexe)r ZappZprocessrrr provided_byIs zAlpm.provided_bycCs*|j|}|r&t|j|dkr&|SdS)z< Find a package by name and some other input criteria rN)r rr vercmpversion)r r r(rrrr find_packageQs zAlpm.find_packagecCst|j|jS)zX vercmp returns: < 0 if ver1 < ver2 0 if ver1 == ver2 > 0 if ver1 > ver2 )r r'r()r Zpackage1Zpackage2rrrcompare_packagesYszAlpm.compare_packagescCs0t||}|t|kr(|||kr(dSdSdS)z5 Searches a sorted list, returns True if found TFN)bisectZ bisect_leftlen)litemirrr _bsearch_listbs zAlpm._bsearch_listcCsH|jjD]:}dd|jD}|||ddrt|j|jSqdS)z9 Returns name of package which provides given file cSsg|] }|dqS)rrrrrrrsrz*Alpm._file_provided_by..rN)r rrr0rrr)r file_namerrrrrr%ms  zAlpm._file_provided_byN) __name__ __module__ __qualname__rrr!r$r&r)r* staticmethodr0r%rrrrr s    r )Z __future__rZtracer.resources.systemrZ distributionr+ZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrZtracer.resources.applicationsrr r rrrrs       packageManagers/__pycache__/dnf.cpython-39.opt-1.pyc000064400000003104151114232410016154 0ustar00a "e`@sTddlmZddlZddlmZedvrPddlZddlm Z Gddde Z dS))absolute_importN)System)ZrhelZfedoraZcentoszcentos-7ZmageiaZsuseZol)Rpmcs4eZdZfddZeddZfddZZS)Dnfc sRtt|jfi|tjdr,d|jd<tjdsDtjdrNd|jd<dS)N$/usr/lib/sysimage/dnf/history.sqliteTsysimage_persistdir/var/lib/dnf/history.sqlite modern_swdb)superr__init__ospathexistsopts)selfkwargs __class__>/usr/lib/python3.9/site-packages/tracer/packageManagers/dnf.pyr s   z Dnf.__init__cCs8|jdr |jdrdSdS|jdr0dSdSdS)Nr rrrz/usr/lib/sysimage/dnf/history/z/var/lib/dnf/history/)rget)rrrr history_path&s   zDnf.history_pathcsP|jdstt||Stjdddd|gtjd}|d}| dS) NZerasedZdnfZ repoqueryz-qz-l)stdoutr ) rrr r package_files subprocessPopenPIPEZ communicatedecodesplit)rpkg_nameZprocessoutrrrr2s   zDnf.package_files)__name__ __module__ __qualname__r propertyrr __classcell__rrrrrs  r) Z __future__rZos.pathr Ztracer.resources.systemrZ distributionrZtracer.packageManagers.rpmrrrrrrs    packageManagers/__pycache__/dnf.cpython-39.pyc000064400000003104151114232410015215 0ustar00a "e`@sTddlmZddlZddlmZedvrPddlZddlm Z Gddde Z dS))absolute_importN)System)ZrhelZfedoraZcentoszcentos-7ZmageiaZsuseZol)Rpmcs4eZdZfddZeddZfddZZS)Dnfc sRtt|jfi|tjdr,d|jd<tjdsDtjdrNd|jd<dS)N$/usr/lib/sysimage/dnf/history.sqliteTsysimage_persistdir/var/lib/dnf/history.sqlite modern_swdb)superr__init__ospathexistsopts)selfkwargs __class__>/usr/lib/python3.9/site-packages/tracer/packageManagers/dnf.pyr s   z Dnf.__init__cCs8|jdr |jdrdSdS|jdr0dSdSdS)Nr rrrz/usr/lib/sysimage/dnf/history/z/var/lib/dnf/history/)rget)rrrr history_path&s   zDnf.history_pathcsP|jdstt||Stjdddd|gtjd}|d}| dS) NZerasedZdnfZ repoqueryz-qz-l)stdoutr ) rrr r package_files subprocessPopenPIPEZ communicatedecodesplit)rpkg_nameZprocessoutrrrr2s   zDnf.package_files)__name__ __module__ __qualname__r propertyrr __classcell__rrrrrs  r) Z __future__rZos.pathr Ztracer.resources.systemrZ distributionrZtracer.packageManagers.rpmrrrrrrs    packageManagers/__pycache__/dpkg.cpython-39.opt-1.pyc000064400000005452151114232410016342 0ustar00a "eZ @stddlmZddlmZedkrpddlmZddlmZddl m Z ddl Z ddl Z ddl Z Gd d d eZdS) )absolute_import)SystemZdebian)IPackageManager)Package)PackagesCollectionNc@sDeZdZdZddZeddZddZdd Zd d Z d d Z dS)Dpkgz" Package manager class - DPKG cKs ||_dS)N)Zopts)selfkwargsr ?/usr/lib/python3.9/site-packages/tracer/packageManagers/dpkg.py__init__'sz Dpkg.__init__cCsdS)Nz/var/log/dpkg.logr )r r r r dpkg_log*sz Dpkg.dpkg_logcCst}t|jd}|D]h}|d}|ddkr2qtt|dd|dd}||kr|dd d}|t||q|S) zp Returns list of packages which were modified between unix_time and present Requires root permissions. r Zupgraderrz%Y-%m-%d %H:%M:%S:) ropenrsplittimemktimestrptimeappendr)r Z unix_timeZnewerloglineZmodifiedpkg_namer r r packages_newer_than-s   zDpkg.packages_newer_thancCsng}ttjd}dd|g}tj|tj|d}|d}|dddD]}tj |rN| |qN|S) z)Returns list of files provided by packagewz dpkg-queryz-L)stdoutstderrr N) rosdevnull subprocessPopenPIPE communicatedecoderpathisfiler)r rfilesZfnullcommandprocessoutfiler r r package_filesDs     zDpkg.package_filescCsfd}tjdd|jgtjd}|d}|d}|D] }|dr:|dd}q:||_ dS) zFFrom database load informations about given package and set them to itNZdpkgz-srrr!z Description:r) r%r&namer'r(r)r startswithstrip description)r packager6r.r/rr r r load_package_infoPs  zDpkg.load_package_infocCsLdd|jg}tj|tjd}|d}|dd}t|ddS)z8Returns name of package which provides given applicationZdlocatez-Sr2rr!r)r3r%r&r'r(r)rr)r Zappr-r.rr r r provided_by^s   zDpkg.provided_byN) __name__ __module__ __qualname____doc__r propertyrrr1r8r9r r r r r s  r)Z __future__rZtracer.resources.systemrZ distributionZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrr%rr#rr r r r s      packageManagers/__pycache__/dpkg.cpython-39.pyc000064400000005452151114232410015403 0ustar00a "eZ @stddlmZddlmZedkrpddlmZddlmZddl m Z ddl Z ddl Z ddl Z Gd d d eZdS) )absolute_import)SystemZdebian)IPackageManager)Package)PackagesCollectionNc@sDeZdZdZddZeddZddZdd Zd d Z d d Z dS)Dpkgz" Package manager class - DPKG cKs ||_dS)N)Zopts)selfkwargsr ?/usr/lib/python3.9/site-packages/tracer/packageManagers/dpkg.py__init__'sz Dpkg.__init__cCsdS)Nz/var/log/dpkg.logr )r r r r dpkg_log*sz Dpkg.dpkg_logcCst}t|jd}|D]h}|d}|ddkr2qtt|dd|dd}||kr|dd d}|t||q|S) zp Returns list of packages which were modified between unix_time and present Requires root permissions. r Zupgraderrz%Y-%m-%d %H:%M:%S:) ropenrsplittimemktimestrptimeappendr)r Z unix_timeZnewerloglineZmodifiedpkg_namer r r packages_newer_than-s   zDpkg.packages_newer_thancCsng}ttjd}dd|g}tj|tj|d}|d}|dddD]}tj |rN| |qN|S) z)Returns list of files provided by packagewz dpkg-queryz-L)stdoutstderrr N) rosdevnull subprocessPopenPIPE communicatedecoderpathisfiler)r rfilesZfnullcommandprocessoutfiler r r package_filesDs     zDpkg.package_filescCsfd}tjdd|jgtjd}|d}|d}|D] }|dr:|dd}q:||_ dS) zFFrom database load informations about given package and set them to itNZdpkgz-srrr!z Description:r) r%r&namer'r(r)r startswithstrip description)r packager6r.r/rr r r load_package_infoPs  zDpkg.load_package_infocCsLdd|jg}tj|tjd}|d}|dd}t|ddS)z8Returns name of package which provides given applicationZdlocatez-Sr2rr!r)r3r%r&r'r(r)rr)r Zappr-r.rr r r provided_by^s   zDpkg.provided_byN) __name__ __module__ __qualname____doc__r propertyrrr1r8r9r r r r r s  r)Z __future__rZtracer.resources.systemrZ distributionZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrr%rr#rr r r r s      packageManagers/__pycache__/ipackageManager.cpython-39.opt-1.pyc000064400000004350151114232410020450 0ustar00a "e@sGdddeZdS)c@sPeZdZddZddZddZddZd d Zd d Zd dZ e ddZ dS)IPackageManagercKstdS)z9This class is 'interface' so you can't create an instanceNNotImplementedError)selfkwargsrJ/usr/lib/python3.9/site-packages/tracer/packageManagers/ipackageManager.py__init__szIPackageManager.__init__cCstdS)z Returns list of packages which were modified between unix_time and present Packages in list should be dictionaries with keys {"name", "modified"} Nr)rZ unix_timerrrpackages_newer_thansz#IPackageManager.packages_newer_thancCstdS)z)Returns list of files provided by packageNr)rpkg_namerrr package_files!szIPackageManager.package_filescCstdS)zFFrom database load informations about given package and set them to itNr)rpackagerrrload_package_info%sz!IPackageManager.load_package_infocCstdS)z8Returns name of package which provides given applicationNr)rZapprrr provided_by)szIPackageManager.provided_bycCstdS)z4Find a package by name and some other input criteriaNr)rr searchrrr find_package-szIPackageManager.find_packagecCstdS)z Compares two packages by their version information Returns: 0 if they are equal 1 if package1 > package2 -1 if package2 > package1 Nr)rZpackage1Zpackage2rrrcompare_packages1sz IPackageManager.compare_packagescCs@z(|d|d}|d|d}Wnty:Yn0|S)N.-)indexrindex ValueError)r rrr_pkg_name_without_version;s z)IPackageManager._pkg_name_without_versionN) __name__ __module__ __qualname__rr r r rrr staticmethodrrrrrrs rN)objectrrrrrpackageManagers/__pycache__/ipackageManager.cpython-39.pyc000064400000004350151114232410017511 0ustar00a "e@sGdddeZdS)c@sPeZdZddZddZddZddZd d Zd d Zd dZ e ddZ dS)IPackageManagercKstdS)z9This class is 'interface' so you can't create an instanceNNotImplementedError)selfkwargsrJ/usr/lib/python3.9/site-packages/tracer/packageManagers/ipackageManager.py__init__szIPackageManager.__init__cCstdS)z Returns list of packages which were modified between unix_time and present Packages in list should be dictionaries with keys {"name", "modified"} Nr)rZ unix_timerrrpackages_newer_thansz#IPackageManager.packages_newer_thancCstdS)z)Returns list of files provided by packageNr)rpkg_namerrr package_files!szIPackageManager.package_filescCstdS)zFFrom database load informations about given package and set them to itNr)rpackagerrrload_package_info%sz!IPackageManager.load_package_infocCstdS)z8Returns name of package which provides given applicationNr)rZapprrr provided_by)szIPackageManager.provided_bycCstdS)z4Find a package by name and some other input criteriaNr)rr searchrrr find_package-szIPackageManager.find_packagecCstdS)z Compares two packages by their version information Returns: 0 if they are equal 1 if package1 > package2 -1 if package2 > package1 Nr)rZpackage1Zpackage2rrrcompare_packages1sz IPackageManager.compare_packagescCs@z(|d|d}|d|d}Wnty:Yn0|S)N.-)indexrindex ValueError)r rrr_pkg_name_without_version;s z)IPackageManager._pkg_name_without_versionN) __name__ __module__ __qualname__rr r r rrr staticmethodrrrrrrs rN)objectrrrrrpackageManagers/__pycache__/portage.cpython-39.opt-1.pyc000064400000006770151114232410017062 0ustar00a "e@sddlmZddlmZddlmZedkrddlmZddlm Z ddl m Z dd l m Z dd lmZdd lmZdd lZdd lZdd lZdd lZGd ddeZd S))absolute_import)unicode_literals)SystemZgentoo)IPackageManager)Package)PackagesCollection) FileOwner)DatabasePermissions) ApplicationsNc@s@eZdZdZddZddZddZdd Zd d Zd d Z dS)Portagez% Package manager class - Portage cKs ||_dS)N)Zopts)selfkwargsrB/usr/lib/python3.9/site-packages/tracer/packageManagers/portage.py__init__,szPortage.__init__cCstdtjstt}tjddgtjd}|d}| dddD]N}| d }t t |dd }||krN|d }||}|t||qN|S) zp Returns list of packages which were modified between unix_time and present Requires root permissions. z/var/log/emerge.logZqlopz-lCstdoutr Nz >>> z%a %b %d %H:%M:%S %Yr)osaccessR_OKr r subprocessPopenPIPE communicatedecodesplittimemktimestrptimeZ_pkg_name_without_versionappendr)r Z unix_timeZnewerprocesspackagespackageZmodifiedpkg_namerrrpackages_newer_than/s   zPortage.packages_newer_thancCsNtjtjd}t||}|j|dgdddd}dd|DS) z)Returns list of files provided by packagevartreeZCONTENTSrrNrcSsg|]}|dqS)r)r).0xrrr Mz)Portage.package_files..)portageZdbrootstrZ dep_bestmatchZdbapiZaux_getr)r r&r(Zcpvcontentsrrr package_filesGs"zPortage.package_filescCsd}|s dS|jdd}tjdd|jgtjd}|d}|d}|D](}|}|drR|dd }qR||_ ||_ dS) zFFrom database load informations about given package and set them to itN/rZeixz-errz Description:r) namerrrrrrstrip startswith descriptioncategory)r r%r6r7r#outlinerrrload_package_infoOs  zPortage.load_package_infocCsf|jd}||j}|rb|jdkr^|jddD]*}tj|r2||}|rT|ndSq2|SdS)z2Returns a package which provides given applicationrzdev-langrN)Z instances_file_provided_byZexer7Zcmdlinerpathisfile)r Zappr#r%argrrr provided_bybs     zPortage.provided_bycCsLtdd}||g}|rH|dd}|jd|j}t|}|j|_|SdS)NT)Z early_outrr2)r r7r3r)r fileZ find_ownerr$r%r3prrrr;os   zPortage._file_provided_byN) __name__ __module__ __qualname____doc__rr'r1r:r?r;rrrrr %s r )Z __future__rrZtracer.resources.systemrZ distributionZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrZgentoolkit.helpersr Ztracer.resources.exceptionsr Ztracer.resources.applicationsr rr-rrr rrrrs          packageManagers/__pycache__/portage.cpython-39.pyc000064400000006770151114232410016123 0ustar00a "e@sddlmZddlmZddlmZedkrddlmZddlm Z ddl m Z dd l m Z dd lmZdd lmZdd lZdd lZdd lZdd lZGd ddeZd S))absolute_import)unicode_literals)SystemZgentoo)IPackageManager)Package)PackagesCollection) FileOwner)DatabasePermissions) ApplicationsNc@s@eZdZdZddZddZddZdd Zd d Zd d Z dS)Portagez% Package manager class - Portage cKs ||_dS)N)Zopts)selfkwargsrB/usr/lib/python3.9/site-packages/tracer/packageManagers/portage.py__init__,szPortage.__init__cCstdtjstt}tjddgtjd}|d}| dddD]N}| d }t t |dd }||krN|d }||}|t||qN|S) zp Returns list of packages which were modified between unix_time and present Requires root permissions. z/var/log/emerge.logZqlopz-lCstdoutr Nz >>> z%a %b %d %H:%M:%S %Yr)osaccessR_OKr r subprocessPopenPIPE communicatedecodesplittimemktimestrptimeZ_pkg_name_without_versionappendr)r Z unix_timeZnewerprocesspackagespackageZmodifiedpkg_namerrrpackages_newer_than/s   zPortage.packages_newer_thancCsNtjtjd}t||}|j|dgdddd}dd|DS) z)Returns list of files provided by packagevartreeZCONTENTSrrNrcSsg|]}|dqS)r)r).0xrrr Mz)Portage.package_files..)portageZdbrootstrZ dep_bestmatchZdbapiZaux_getr)r r&r(Zcpvcontentsrrr package_filesGs"zPortage.package_filescCsd}|s dS|jdd}tjdd|jgtjd}|d}|d}|D](}|}|drR|dd }qR||_ ||_ dS) zFFrom database load informations about given package and set them to itN/rZeixz-errz Description:r) namerrrrrrstrip startswith descriptioncategory)r r%r6r7r#outlinerrrload_package_infoOs  zPortage.load_package_infocCsf|jd}||j}|rb|jdkr^|jddD]*}tj|r2||}|rT|ndSq2|SdS)z2Returns a package which provides given applicationrzdev-langrN)Z instances_file_provided_byZexer7Zcmdlinerpathisfile)r Zappr#r%argrrr provided_bybs     zPortage.provided_bycCsLtdd}||g}|rH|dd}|jd|j}t|}|j|_|SdS)NT)Z early_outrr2)r r7r3r)r fileZ find_ownerr$r%r3prrrr;os   zPortage._file_provided_byN) __name__ __module__ __qualname____doc__rr'r1r:r?r;rrrrr %s r )Z __future__rrZtracer.resources.systemrZ distributionZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrZgentoolkit.helpersr Ztracer.resources.exceptionsr Ztracer.resources.applicationsr rr-rrr rrrrs          packageManagers/__pycache__/rpm.cpython-39.opt-1.pyc000064400000014610151114232410016207 0ustar00a "e@sddlmZddlmZedvrddlmZddlmZddl m Z ddl m Z dd l mZmZdd lmZdd lZdd lZdd lZGd d d eZd S))absolute_import)System)ZfedoraZrhelZcentoszcentos-7ZmageiaZol)listdir)IPackageManager)Package)PackagesCollection)LockedDatabaseDatabasePermissions)PY3Nc@steZdZdZddZeddZddZdd Zd d Z d d Z ddZ ddZ ddZ ddZddZddZdS)Rpmz! Package manager class - RPM cKs ||_dSN)opts)selfkwargsr>/usr/lib/python3.9/site-packages/tracer/packageManagers/rpm.py__init__*sz Rpm.__init__cCstSr )NotImplemented)rrrr history_path-szRpm.history_pathc Cstj|jstgS|jdr(d}nd}zbt}|}t |}tj |_ | }| ||g|D]}|t|d|dql|WStjy}z$t|dkrtntWYd}~n d}~00dS)zp Returns list of packages which were modified between unix_time and present Requires root permissions. modern_swdbz SELECT DISTINCT rpm.name, trans.dt_end AS end FROM trans JOIN trans_item JOIN rpm ON trans.id=trans_item.trans_id AND trans_item.item_id=rpm.item_id WHERE trans.dt_begin > ? ORDER BY rpm.name aJ SELECT DISTINCT pkgtups.name, trans_end.timestamp AS end FROM trans_beg JOIN trans_end JOIN trans_data_pkgs JOIN pkgtups ON trans_beg.tid=trans_end.tid AND trans_data_pkgs.tid=trans_beg.tid AND trans_data_pkgs.pkgtupid=pkgtups.pkgtupid WHERE trans_beg.timestamp > ? ORDER BY pkgtups.name nameendzdatabase is lockedN)ospathexistsrrrget_database_filesqlite3ZconnectZRowZ row_factorycursorZexecuteZfetchallappendrZOperationalErrorstrr r ) rZ unix_timeZsqlpackagesZsqliteZconnrresulterrrpackages_newer_than0s"     zRpm.packages_newer_thancCsdt}|d|}t|}|s$gStrDt|d}dd|DSt|d}dd|DSdS)z Returns list of files provided by package See also: http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch04s02s03.html rrcSsg|] }|jqSr)r).0xrrr qz%Rpm.package_files..cSsg|] }|dqS)rr)r&frrrr(tr)N)rpmTransactionSetdbMatchlistr filesfi)rpkg_nametsmir"r/rrr package_filesbs zRpm.package_filescCs||}t}|d|}|D]h}|tj|dkr"|tj|dkr"|tj|dkr"|tj|dkr"t|}| |||Sq"dS)Nrrr) _splitEvrar+r,r- RPMTAG_EPOCHRPMTAG_VERSIONRPMTAG_RELEASEZ RPMTAG_ARCHr_load_package_info_from_hdr)rrevrar2r3hdrpackagerrr find_packagevs  H  zRpm.find_packagec Cs|sdSt}|d|j}d}|D]r}|dur8|}q&tt|tjt|tjt|tjft|tjt|tjt|tjf}|dkr&|}q&|durdS| ||dS)zFFrom database load informations about given package and set them to itNr) r+r,r-r labelComparer!r8r9r:r;)rr>r2r3Zlatestr=Zcomparerrrload_package_infos *&zRpm.load_package_infocCs<tt|jt|jt|jft|jt|jt|jfS)zf labelCompare returns: 0 if the EVR matches 1 if EVR(1) > EVR(2) -1 if EVR(2) > EVR(1) )r+rAr!epochversionrelease)rZp1Zp2rrrcompare_packagesszRpm.compare_packagescCsh|jd}||j}|rd|jdkr`|ddD]*}tj|r4||}|rV|ndSq4|SdS)z8Returns name of package which provides given applicationrzDevelopment/LanguagesrN)Z instances_file_provided_byZexecategoryZcmdlinerrisfile)rZappZprocessr>argrrr provided_bys     zRpm.provided_byc Cs|d}||dd}|d|d}||d|}|d|d}||d|}|d}|dkrvd} n |d|} | |||fS)z Derived from rpmUtils.miscutils.splitFilename https://github.com/rpm-software-management/yum/blob/master/rpmUtils/miscutils.py Given: 9-123a.ia64 Return: (9, 123a, 1, ia64) .rN-:r@)rfindfind) rr<Z archIndexZarchZrelIndexrelZverIndexZverZ epochIndexrCrrrr7s   zRpm._splitEvracCsH|tj|_|tj|_|tj}|r,||_|tj|_|tj |_ dSr ) r+ZRPMTAG_SUMMARY description RPMTAG_GROUPrHr8rCr9rDr:rE)rr>r=rCrrrr;s    zRpm._load_package_info_from_hdrcCsJt}|d|}|dkr$dSt|}t|tj}|tj|_|S)z1Returns name of package which provides given fileZ basenamesrN) r+r,r-countnextrZ RPMTAG_NAMErSrH)rfiler2ZdbpkgprrrrGs   zRpm._file_provided_bycCsP|jdr|jStt|jddD]&}|dr$|dr$|j|Sq$dS)z)Returns path to yum history database filerT)reversezhistory-z.sqliteN)rrrsortedr startswithendswith)rrVrrrrs  zRpm._database_fileN)__name__ __module__ __qualname____doc__rpropertyrr%r4r?rBrFrKr7r;rGrrrrrr #s 2   r )Z __future__rZtracer.resources.systemrZ distributionrrZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrZtracer.resources.exceptionsr r Ztracer.resources.pycompr rr+r rrrrs        packageManagers/__pycache__/rpm.cpython-39.pyc000064400000014610151114232410015250 0ustar00a "e@sddlmZddlmZedvrddlmZddlmZddl m Z ddl m Z dd l mZmZdd lmZdd lZdd lZdd lZGd d d eZd S))absolute_import)System)ZfedoraZrhelZcentoszcentos-7ZmageiaZol)listdir)IPackageManager)Package)PackagesCollection)LockedDatabaseDatabasePermissions)PY3Nc@steZdZdZddZeddZddZdd Zd d Z d d Z ddZ ddZ ddZ ddZddZddZdS)Rpmz! Package manager class - RPM cKs ||_dSN)opts)selfkwargsr>/usr/lib/python3.9/site-packages/tracer/packageManagers/rpm.py__init__*sz Rpm.__init__cCstSr )NotImplemented)rrrr history_path-szRpm.history_pathc Cstj|jstgS|jdr(d}nd}zbt}|}t |}tj |_ | }| ||g|D]}|t|d|dql|WStjy}z$t|dkrtntWYd}~n d}~00dS)zp Returns list of packages which were modified between unix_time and present Requires root permissions. modern_swdbz SELECT DISTINCT rpm.name, trans.dt_end AS end FROM trans JOIN trans_item JOIN rpm ON trans.id=trans_item.trans_id AND trans_item.item_id=rpm.item_id WHERE trans.dt_begin > ? ORDER BY rpm.name aJ SELECT DISTINCT pkgtups.name, trans_end.timestamp AS end FROM trans_beg JOIN trans_end JOIN trans_data_pkgs JOIN pkgtups ON trans_beg.tid=trans_end.tid AND trans_data_pkgs.tid=trans_beg.tid AND trans_data_pkgs.pkgtupid=pkgtups.pkgtupid WHERE trans_beg.timestamp > ? ORDER BY pkgtups.name nameendzdatabase is lockedN)ospathexistsrrrget_database_filesqlite3ZconnectZRowZ row_factorycursorZexecuteZfetchallappendrZOperationalErrorstrr r ) rZ unix_timeZsqlpackagesZsqliteZconnrresulterrrpackages_newer_than0s"     zRpm.packages_newer_thancCsdt}|d|}t|}|s$gStrDt|d}dd|DSt|d}dd|DSdS)z Returns list of files provided by package See also: http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch04s02s03.html rrcSsg|] }|jqSr)r).0xrrr qz%Rpm.package_files..cSsg|] }|dqS)rr)r&frrrr(tr)N)rpmTransactionSetdbMatchlistr filesfi)rpkg_nametsmir"r/rrr package_filesbs zRpm.package_filescCs||}t}|d|}|D]h}|tj|dkr"|tj|dkr"|tj|dkr"|tj|dkr"t|}| |||Sq"dS)Nrrr) _splitEvrar+r,r- RPMTAG_EPOCHRPMTAG_VERSIONRPMTAG_RELEASEZ RPMTAG_ARCHr_load_package_info_from_hdr)rrevrar2r3hdrpackagerrr find_packagevs  H  zRpm.find_packagec Cs|sdSt}|d|j}d}|D]r}|dur8|}q&tt|tjt|tjt|tjft|tjt|tjt|tjf}|dkr&|}q&|durdS| ||dS)zFFrom database load informations about given package and set them to itNr) r+r,r-r labelComparer!r8r9r:r;)rr>r2r3Zlatestr=Zcomparerrrload_package_infos *&zRpm.load_package_infocCs<tt|jt|jt|jft|jt|jt|jfS)zf labelCompare returns: 0 if the EVR matches 1 if EVR(1) > EVR(2) -1 if EVR(2) > EVR(1) )r+rAr!epochversionrelease)rZp1Zp2rrrcompare_packagesszRpm.compare_packagescCsh|jd}||j}|rd|jdkr`|ddD]*}tj|r4||}|rV|ndSq4|SdS)z8Returns name of package which provides given applicationrzDevelopment/LanguagesrN)Z instances_file_provided_byZexecategoryZcmdlinerrisfile)rZappZprocessr>argrrr provided_bys     zRpm.provided_byc Cs|d}||dd}|d|d}||d|}|d|d}||d|}|d}|dkrvd} n |d|} | |||fS)z Derived from rpmUtils.miscutils.splitFilename https://github.com/rpm-software-management/yum/blob/master/rpmUtils/miscutils.py Given: 9-123a.ia64 Return: (9, 123a, 1, ia64) .rN-:r@)rfindfind) rr<Z archIndexZarchZrelIndexrelZverIndexZverZ epochIndexrCrrrr7s   zRpm._splitEvracCsH|tj|_|tj|_|tj}|r,||_|tj|_|tj |_ dSr ) r+ZRPMTAG_SUMMARY description RPMTAG_GROUPrHr8rCr9rDr:rE)rr>r=rCrrrr;s    zRpm._load_package_info_from_hdrcCsJt}|d|}|dkr$dSt|}t|tj}|tj|_|S)z1Returns name of package which provides given fileZ basenamesrN) r+r,r-countnextrZ RPMTAG_NAMErSrH)rfiler2ZdbpkgprrrrGs   zRpm._file_provided_bycCsP|jdr|jStt|jddD]&}|dr$|dr$|j|Sq$dS)z)Returns path to yum history database filerT)reversezhistory-z.sqliteN)rrrsortedr startswithendswith)rrVrrrrs  zRpm._database_fileN)__name__ __module__ __qualname____doc__rpropertyrr%r4r?rBrFrKr7r;rGrrrrrr #s 2   r )Z __future__rZtracer.resources.systemrZ distributionrrZipackageManagerrZtracer.resources.packagerZtracer.resources.collectionsrZtracer.resources.exceptionsr r Ztracer.resources.pycompr rr+r rrrrs        packageManagers/__pycache__/yum.cpython-39.opt-1.pyc000064400000001261151114232410016221 0ustar00a "eX@sDddlmZddlmZedvr@ddlmZGdddeZdS))absolute_import)System)ZfedoraZrhelZcentoszcentos-7Zol)Rpmc@seZdZeddZdS)YumcCsdS)Nz/var/lib/yum/history/)selfrr>/usr/lib/python3.9/site-packages/tracer/packageManagers/yum.py history_pathszYum.history_pathN)__name__ __module__ __qualname__propertyr rrrrrsrN)Z __future__rZtracer.resources.systemrZ distributionZtracer.packageManagers.rpmrrrrrrs    packageManagers/__pycache__/yum.cpython-39.pyc000064400000001261151114232410015262 0ustar00a "eX@sDddlmZddlmZedvr@ddlmZGdddeZdS))absolute_import)System)ZfedoraZrhelZcentoszcentos-7Zol)Rpmc@seZdZeddZdS)YumcCsdS)Nz/var/lib/yum/history/)selfrr>/usr/lib/python3.9/site-packages/tracer/packageManagers/yum.py history_pathszYum.history_pathN)__name__ __module__ __qualname__propertyr rrrrrsrN)Z __future__rZtracer.resources.systemrZ distributionZtracer.packageManagers.rpmrrrrrrs    packageManagers/README.md000064400000000636151114232410011073 0ustar00# Package managers Every package manager module should inherit `IPackageManger` class and implement its methods: - `packages_newer_than(self, unix_time)` - `package_files(self, pkg_name)` - `load_package_info(self, package)` - `provided_by(self, app)` Also there should be unit test for every package manager. Please see [dnf test](https://github.com/FrostyX/tracer/blob/develop/tests/test_dnf.py) for example. packageManagers/__init__.py000064400000000000151114232410011706 0ustar00packageManagers/alpm.py000064400000006512151114232410011116 0ustar00#-*- coding: utf-8 -*- # alpm.py # # Copyright (C) 2016 Patrick Griffis # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from tracer.resources.system import System if System.distribution() in ["arch", "archarm"]: import bisect from .ipackageManager import IPackageManager from tracer.resources.package import Package from tracer.resources.collections import PackagesCollection from tracer.resources.applications import Applications import pyalpm class Alpm(IPackageManager): def __init__(self, *args, **kwargs): self.opts = kwargs self.handle = pyalpm.Handle('/', '/var/lib/pacman') self.db = self.handle.get_localdb() def packages_newer_than(self, unix_time): """ Returns list of packages which were modified between unix_time and present """ new_pkgs = PackagesCollection() for pkg in self.db.pkgcache: if pkg.installdate > unix_time: new_pkgs.append(Package(pkg.name, pkg.installdate)) return new_pkgs def package_files(self, pkg_name): """ Returns list of files provided by package """ pkg = self.db.get_pkg(pkg_name) if not pkg: return [] return ['/' + f[0] for f in pkg.files] def load_package_info(self, package): """ From database load informations about given package and set them to it """ if not package: return pkg = self.db.get_pkg(package.name) if not pkg: return package.description = pkg.desc package.modified = pkg.installdate # Don't have categories def provided_by(self, app): """ Returns name of package which provides given application """ # We need a full path to the binary process = app.instances[0] return self._file_provided_by(process.exe) def find_package(self, pkg_name, version): """ Find a package by name and some other input criteria """ pkg = self.db.get_pkg(pkg_name) if pkg and pyalpm.vercmp(pkg.version, version) == 0: return pkg def compare_packages(self, package1, package2): """ vercmp returns: < 0 if ver1 < ver2 0 if ver1 == ver2 > 0 if ver1 > ver2 """ return pyalpm.vercmp(package1.version, package2.version) @staticmethod def _bsearch_list(l, item): """ Searches a sorted list, returns True if found """ i = bisect.bisect_left(l, item) if i != len(l) and l[i] == item: return True else: return False def _file_provided_by(self, file_name): """ Returns name of package which provides given file """ # This is a bit slow for pkg in self.db.pkgcache: files = [f[0] for f in pkg.files] if self._bsearch_list(files, file_name[1:]): return Package(pkg.name, pkg.installdate) else: return None packageManagers/dnf.py000064400000004140151114232410010727 0ustar00#-*- coding: utf-8 -*- # dnf.py # Module to work with DNF package manager class # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import import os.path from tracer.resources.system import System if System.distribution() in ["rhel", "fedora", "centos", "centos-7", "mageia", "suse", "ol"]: import subprocess from tracer.packageManagers.rpm import Rpm class Dnf(Rpm): def __init__(self, **kwargs): super(Dnf, self).__init__(**kwargs) if os.path.exists('/usr/lib/sysimage/dnf/history.sqlite'): self.opts['sysimage_persistdir'] = True if os.path.exists('/usr/lib/sysimage/dnf/history.sqlite') or os.path.exists('/var/lib/dnf/history.sqlite'): self.opts['modern_swdb'] = True @property def history_path(self): if self.opts.get('modern_swdb'): if self.opts.get('sysimage_persistdir'): return '/usr/lib/sysimage/dnf/history.sqlite' else: return '/var/lib/dnf/history.sqlite' if self.opts.get('sysimage_persistdir'): return '/usr/lib/sysimage/dnf/history/' else: return '/var/lib/dnf/history/' def package_files(self, pkg_name): if not self.opts.get("erased"): return super(Dnf, self).package_files(pkg_name) # TODO Running an external command is tooooo slow, use python API instead process = subprocess.Popen(["dnf", "repoquery", "-q", "-l", pkg_name], stdout=subprocess.PIPE) out = process.communicate()[0] return out.decode().split("\n") packageManagers/dpkg.py000064400000006132151114232410011110 0ustar00#-*- coding: utf-8 -*- # dpkg.py # Module to work with dpkg based package managers # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from tracer.resources.system import System if System.distribution() == "debian": from .ipackageManager import IPackageManager from tracer.resources.package import Package from tracer.resources.collections import PackagesCollection import subprocess import time import os class Dpkg(IPackageManager): """ Package manager class - DPKG """ # noinspection PyMissingConstructor def __init__(self, **kwargs): self.opts = kwargs @property def dpkg_log(self): return '/var/log/dpkg.log' def packages_newer_than(self, unix_time): """ Returns list of packages which were modified between unix_time and present Requires root permissions. """ newer = PackagesCollection() log = open(self.dpkg_log, 'r') for line in log: line = line.split(" ") if line[2] != "upgrade": continue # There actually should be %e instead of %d modified = time.mktime( time.strptime(line[0] + " " + line[1], "%Y-%m-%d %H:%M:%S")) if modified >= unix_time: pkg_name = line[3].split(":")[0] newer.append(Package(pkg_name, modified)) return newer def package_files(self, pkg_name): """Returns list of files provided by package""" files = [] fnull = open(os.devnull, 'w') command = ['dpkg-query', '-L', pkg_name] process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=fnull) out = process.communicate()[0] for file in out.decode().split('\n')[:-1]: if os.path.isfile(file): files.append(file) return files def load_package_info(self, package): """From database load informations about given package and set them to it""" description = None process = subprocess.Popen(['dpkg', '-s', package.name], stdout=subprocess.PIPE) out = process.communicate()[0] out = out.decode().split('\n') for line in out: if line.startswith("Description:"): description = line.split("Description:")[1].strip() package.description = description def provided_by(self, app): """Returns name of package which provides given application""" command = ['dlocate', '-S', app.name] process = subprocess.Popen(command, stdout=subprocess.PIPE) pkg_name = process.communicate()[0] pkg_name = pkg_name.decode().split('\n')[0] return Package(pkg_name.split(':')[0]) packageManagers/ipackageManager.py000064400000004277151114232410013232 0ustar00#-*- coding: utf-8 -*- # ipackageManager.py # This class should be inherited by any other package manager # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # class IPackageManager(object): def __init__(self, **kwargs): """This class is 'interface' so you can't create an instance""" raise NotImplementedError def packages_newer_than(self, unix_time): """ Returns list of packages which were modified between unix_time and present Packages in list should be dictionaries with keys {"name", "modified"} """ raise NotImplementedError def package_files(self, pkg_name): """Returns list of files provided by package""" raise NotImplementedError def load_package_info(self, package): """From database load informations about given package and set them to it""" raise NotImplementedError def provided_by(self, app): """Returns name of package which provides given application""" raise NotImplementedError def find_package(self, pkg_name, search): """Find a package by name and some other input criteria""" raise NotImplementedError def compare_packages(self, package1, package2): """ Compares two packages by their version information Returns: 0 if they are equal 1 if package1 > package2 -1 if package2 > package1 """ raise NotImplementedError @staticmethod def _pkg_name_without_version(pkg_name): try: pkg_name = pkg_name[:pkg_name.index('.')] # Cut from first . to end pkg_name = pkg_name[:pkg_name.rindex('-')] # Cut from last - to end except ValueError: pass return pkg_name packageManagers/portage.py000064400000007637151114232410011637 0ustar00#-*- coding: utf-8 -*- # portage.py # Module to work with portage package manager class # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from __future__ import unicode_literals from tracer.resources.system import System if System.distribution() == "gentoo": from .ipackageManager import IPackageManager from tracer.resources.package import Package from tracer.resources.collections import PackagesCollection from gentoolkit.helpers import FileOwner from tracer.resources.exceptions import DatabasePermissions from tracer.resources.applications import Applications import os import portage import subprocess import time class Portage(IPackageManager): """ Package manager class - Portage """ # noinspection PyMissingConstructor def __init__(self, **kwargs): self.opts = kwargs def packages_newer_than(self, unix_time): """ Returns list of packages which were modified between unix_time and present Requires root permissions. """ if not os.access('/var/log/emerge.log', os.R_OK): raise DatabasePermissions newer = PackagesCollection() process = subprocess.Popen(['qlop', '-lC'], stdout=subprocess.PIPE) packages = process.communicate()[0] for package in packages.decode().split('\n')[:-1]: package = package.split(" >>> ") # There actually should be %e instead of %d modified = time.mktime(time.strptime(package[0], "%a %b %d %H:%M:%S %Y")) if modified >= unix_time: pkg_name = package[1] # Package name with version, let's cut it off pkg_name = self._pkg_name_without_version(pkg_name) newer.append(Package(pkg_name, modified)) return newer def package_files(self, pkg_name): """Returns list of files provided by package""" vartree = portage.db[portage.root]['vartree'] cpv = str(vartree.dep_bestmatch(pkg_name)) contents = vartree.dbapi.aux_get(cpv, ['CONTENTS'])[0].split('\n')[:-1] return [x.split()[1] for x in contents] def load_package_info(self, package): """From database load informations about given package and set them to it""" description = None if not package: return None category = package.name.split('/')[0] process = subprocess.Popen(['eix', '-e', package.name], stdout=subprocess.PIPE) out = process.communicate()[0] out = out.decode().split('\n') for line in out: line = line.strip() if line.startswith("Description:"): description = line.split("Description:")[1].strip() package.description = description package.category = category def provided_by(self, app): """Returns a package which provides given application""" process = app.instances[0] # @TODO Reimplement for all processes package = self._file_provided_by(process.exe) if package: if package.category == 'dev-lang': for arg in process.cmdline[1:]: if os.path.isfile(arg): package = self._file_provided_by(arg) return package if package else None return package return None def _file_provided_by(self, file): find_owner = FileOwner(early_out=True) packages = find_owner([file]) if packages: package = packages[0][0] name = package.category + '/' + package.name p = Package(name) p.category = package.category return p return None packageManagers/rpm.py000064400000015616151114232410010770 0ustar00#-*- coding: utf-8 -*- # rpm.py # Base RPM package manager class # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from tracer.resources.system import System if System.distribution() in ["fedora", "rhel", "centos", "centos-7", "mageia", "ol"]: from os import listdir from .ipackageManager import IPackageManager from tracer.resources.package import Package from tracer.resources.collections import PackagesCollection from tracer.resources.exceptions import LockedDatabase, DatabasePermissions from tracer.resources.pycomp import PY3 import sqlite3 import rpm import os class Rpm(IPackageManager): """ Package manager class - RPM """ # noinspection PyMissingConstructor def __init__(self, **kwargs): self.opts = kwargs @property def history_path(self): return NotImplemented def packages_newer_than(self, unix_time): """ Returns list of packages which were modified between unix_time and present Requires root permissions. """ # Package manager wasn't used yet if not os.path.exists(self.history_path): return PackagesCollection([]) if self.opts.get('modern_swdb'): sql = """ SELECT DISTINCT rpm.name, trans.dt_end AS end FROM trans JOIN trans_item JOIN rpm ON trans.id=trans_item.trans_id AND trans_item.item_id=rpm.item_id WHERE trans.dt_begin > ? ORDER BY rpm.name """ else: sql = """ SELECT DISTINCT pkgtups.name, trans_end.timestamp AS end FROM trans_beg JOIN trans_end JOIN trans_data_pkgs JOIN pkgtups ON trans_beg.tid=trans_end.tid AND trans_data_pkgs.tid=trans_beg.tid AND trans_data_pkgs.pkgtupid=pkgtups.pkgtupid WHERE trans_beg.timestamp > ? ORDER BY pkgtups.name """ try: packages = PackagesCollection() sqlite = self._database_file() conn = sqlite3.connect(sqlite) conn.row_factory = sqlite3.Row cursor = conn.cursor() cursor.execute(sql, [unix_time]) for result in cursor.fetchall(): packages.append(Package(result['name'], result['end'])) return packages except sqlite3.OperationalError as e: raise LockedDatabase() if str(e) == 'database is locked' else DatabasePermissions() def package_files(self, pkg_name): """ Returns list of files provided by package See also: http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch04s02s03.html """ ts = rpm.TransactionSet() mi = ts.dbMatch("name", pkg_name) packages = list(mi) # Tracer will not find uninstalled applications if not packages: return [] if PY3: files = rpm.files(packages[0]) return [x.name for x in files] else: files = rpm.fi(packages[0]) return [f[0] for f in files] def find_package(self, name, evra): evra = self._splitEvra(evra) ts = rpm.TransactionSet() mi = ts.dbMatch("name", name) for hdr in mi: if hdr[rpm.RPMTAG_EPOCH] == evra[0] and hdr[rpm.RPMTAG_VERSION] == evra[1] and hdr[rpm.RPMTAG_RELEASE] == evra[2] and hdr[rpm.RPMTAG_ARCH] == evra[3]: package = Package(name) self._load_package_info_from_hdr(package, hdr) return package return None def load_package_info(self, package): """From database load informations about given package and set them to it""" if not package: return None ts = rpm.TransactionSet() mi = ts.dbMatch("name", package.name) """ Find the latest one if there are multiple versions""" latest = None for hdr in mi: if latest is None: latest = hdr else: compare = rpm.labelCompare((str(latest[rpm.RPMTAG_EPOCH]), str(latest[rpm.RPMTAG_VERSION]), str(latest[rpm.RPMTAG_RELEASE])), (str(hdr[rpm.RPMTAG_EPOCH]), str(hdr[rpm.RPMTAG_VERSION]), str(hdr[rpm.RPMTAG_RELEASE]))) if compare == -1: latest = hdr if latest is None: return self._load_package_info_from_hdr(package, latest) def compare_packages(self, p1, p2): """ labelCompare returns: 0 if the EVR matches 1 if EVR(1) > EVR(2) -1 if EVR(2) > EVR(1) """ return rpm.labelCompare((str(p1.epoch), str(p1.version), str(p1.release)), (str(p2.epoch), str(p2.version), str(p2.release))) def provided_by(self, app): """Returns name of package which provides given application""" # `rpm -qf ...` needs full path to binary, not only its name process = app.instances[0] # @TODO Reimplement for all processes package = self._file_provided_by(process.exe) if package: # If package is interpreter, return the package providing that interpreted file if package.category == 'Development/Languages': for arg in process.cmdline()[1:]: if os.path.isfile(arg): package = self._file_provided_by(arg) return package if package else None return package return None def _splitEvra(self, evra): """ Derived from rpmUtils.miscutils.splitFilename https://github.com/rpm-software-management/yum/blob/master/rpmUtils/miscutils.py Given: 9-123a.ia64 Return: (9, 123a, 1, ia64) """ archIndex = evra.rfind('.') arch = evra[archIndex + 1:] relIndex = evra[:archIndex].rfind('-') rel = evra[relIndex + 1:archIndex] verIndex = evra[:relIndex].rfind('-') ver = evra[verIndex + 1:relIndex] epochIndex = evra.find(':') if epochIndex == -1: epoch = None else: epoch = evra[:epochIndex] return epoch, ver, rel, arch def _load_package_info_from_hdr(self, package, hdr): package.description = hdr[rpm.RPMTAG_SUMMARY] package.category = hdr[rpm.RPMTAG_GROUP] epoch = hdr[rpm.RPMTAG_EPOCH] if epoch: package.epoch = epoch package.version = hdr[rpm.RPMTAG_VERSION] package.release = hdr[rpm.RPMTAG_RELEASE] def _file_provided_by(self, file): """Returns name of package which provides given file""" ts = rpm.TransactionSet() db = ts.dbMatch("basenames", file) if db.count() == 0: return None pkg = next(db) p = Package(pkg[rpm.RPMTAG_NAME]) p.category = pkg[rpm.RPMTAG_GROUP] return p def _database_file(self): """Returns path to yum history database file""" if self.opts.get('modern_swdb'): return self.history_path for file in sorted(listdir(self.history_path), reverse=True): if file.startswith("history-") and file.endswith(".sqlite"): return self.history_path + file packageManagers/yum.py000064400000002130151114232410010767 0ustar00#-*- coding: utf-8 -*- # yum.py # Module to work with YUM package manager class # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from tracer.resources.system import System if System.distribution() in ["fedora", "rhel", "centos", "centos-7", "ol"]: from tracer.packageManagers.rpm import Rpm class Yum(Rpm): @property def history_path(self): return '/var/lib/yum/history/' resources/__pycache__/package.cpython-39.pyc000064400000003022151114232410015001 0ustar00a "eJ@sddlmZGdddZdS))absolute_importc@sfeZdZdZdZdZdZdZdZdZ dZ dddZ ddZ ddZ d d Zd d Zd dZddZdS)PackagezRepresents linux packageNcCs||_||_dSN)namemodified)selfrrrrrrrr __repr__-szPackage.__repr__cCs|jSrrrrrr __str__0szPackage.__str__cCs t|jSr)hashrrrrr __hash__3szPackage.__hash__cCs||dSr)Zload_package_info)rZpackage_managerrrr load_info6szPackage.load_info)N)__name__ __module__ __qualname____doc__rr descriptioncategoryZepochversionreleaser rrrrrrrrrr rs rN)Z __future__rrrrrr s resources/__pycache__/processes.cpython-39.opt-1.pyc000064400000024541151114232410016364 0ustar00a "eq#@sddlmZddlmZddlZddlZddlZddlZddlmZm Z ddl m Z ddl m Z Gdd d eZGd d d eZGd d d eZGddde eeZGdddeZdS))ProcessesCollection)FilenameCleanerN)PIPEPopen)Timer)with_metaclassc@s$eZdZeddZeddZdS) ProcessescCs*z tWSty$tYS0dSN)psutilpidsAttributeErrorZ get_pid_listrr>/usr/lib/python3.9/site-packages/tracer/resources/processes.pyr !s  zProcesses.pidsc CsRt}tD]>}z|t|Wqtjy8YqtjyJYq0q|Sr )rr r appendProcessr Z NoSuchProcess AccessDenied)Z processespidrrrall(s z Processes.allN)__name__ __module__ __qualname__ staticmethodr rrrrrr s r c@seZdZdZd!ddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ d"ddZddZddZd#dd ZdS)$ProcessWrappera Wrapper for ``psutil.Process class`` Library ``psutil`` is not backward compatible from version 2.x.x to 1.x.x. Purpose of this class is cover incompatibility in ``psutil.Process`` class and provide interface of new version. It allows using new interface even with old version of ``psutil``. Note that, for performance reasons, process information is cached at object creation. To force a refresh, invoke the ``rebuild_cache()`` method. NcCst||_|dSr )r r_process rebuild_cacheselfrrrr__init__As zProcessWrapper.__init__cCs t|jSr )boolrrrrr __nonzero__EszProcessWrapper.__nonzero__cCs|jjgdd|_dS)N)nameexecmdlineppidusername create_time)attrs)rZas_dict _procdictr rrrrHszProcessWrapper.rebuild_cachecCs|z\|ddkrZ|d|dvrZt|ddkrZ|dddd}d|WSWntjypYn0|dS) Nr"Zsshdr#r$r@rzssh-{0}-session)_attrlensplitformatr r)rr&rrrr"Ks&zProcessWrapper.namecCs |dS)Nr#r+r rrrr#WszProcessWrapper.execCs |dS)Nr$r/r rrrr$ZszProcessWrapper.cmdlinecCs |dS)Nr%r/r rrrr%]szProcessWrapper.ppidcCs |dS)Nparentr/r rrrr0`szProcessWrapper.parentcCs |dS)Nr&r/r rrrr&cszProcessWrapper.usernamecCs |dS)Nr'r/r rrrr'fszProcessWrapper.create_timeFcCsZd|}||jvrPz|j||j|<Wn$tyN|j||j|<Yn0|j|S)Nz children-{0})r.r)rchildrenr Z get_children)r recursivekeyrrrr1is   zProcessWrapper.childrencCsN||jvrDt|j|}z||j|<WntyB||j|<Yn0|j|Sr )r)getattrr TypeError)rr"attrrrrr+rs   zProcessWrapper._attrcCs t|j|Sr )r4r)ritemrrr __getattr__{szProcessWrapper.__getattr__TcCs^d|}||jvrTz|jj|d|j|<Wn&tyR|jj|d|j|<Yn0|j|S)Nzmemory_maps-{0})grouped)r.r)r memory_mapsr Zget_memory_maps)rr9r3rrrr:s   zProcessWrapper.memory_maps)N)F)T)rrr__doc__rr!rr"r#r$r%r0r&r'r1r+r8r:rrrrr3s    rcs(eZdZdZfddZddZZS) ProcessMetaz Caching metaclass that ensures that only one ``Process`` object is ever instantiated for any given PID. The cache can be cleared by calling ``Process.reset_cache()``. Based on https://stackoverflow.com/a/33458129 cs6tt|||fdd}|td|dS)Ncs i_dSr )_cacherclsrr reset_cachesz)ProcessMeta.__init__..reset_cacher@)superr<rsetattr)r?r"basesZ attributesr@ __class__r>rrs zProcessMeta.__init__cOsV|d}||jvrL|j|g|Ri|}|j|g|Ri|||j|<|j|S)Nr)r=__new__r)r?argskwargsrrrrr__call__s   zProcessMeta.__call__)rrrr;rrI __classcell__rrrDrr<s r<cseZdZdZddZddZddZedd d Ze d d Z d dZ fddZ dfdd Z e fddZe ddZe ddZe ddZe ddZZS) raS Represent the process instance uniquely identifiable through PID For all class properties and methods, please see http://pythonhosted.org/psutil/#process-class Below listed are only reimplemented ones. For performance reasons, instances are cached based on PID, and multiple instantiations of a ``Process`` object with the same PID will return the same object. To clear the cache, invoke ``Process.reset_cache()``. Additionally, as with ``ProcessWrapper``, process information is cached at object creation. To force a refresh, invoke the ``rebuild_cache()`` method on the object. cCs |j|jkS)zBFor our purposes, two processes are equal when they have same name)rrprocessrrr__eq__szProcess.__eq__cCs || Sr )rMrKrrr__ne__szProcess.__ne__cCs t|jSr )hashrr rrr__hash__szProcess.__hash__?cCsTtdd|gttd}t||j}z$|||jdkW|S|0dS)z Process arguments could be referring to files on remote filesystems and os.path.isfile will hang forever if the shared FS is offline. Instead, use a subprocess that we can time out if we can't reach some file. testz-f)stdoutstderrrN)rrrkillstartZ communicate returncodecancel)Z file_pathtimeoutrLZtimerrrr safe_isfiles  zProcess.safe_isfilecCsdg}|D]}|t|jq |ddD]&}tj|sFq4t |r4||q4t |SNr) r:rrstrippathr$osisabsrrZsorted)rfilesZmmapargrrrras    z Process.filescCs|rt|SdS)zGThe parent process casted from ``psutil.Process`` to tracer ``Process``N)r%rr rrrr0s zProcess.parentcs*ztt|WSty$YdS0dS)zcThe user who owns the process. If user was deleted in the meantime, ``None`` is returned instead.N)rArr&KeyErrorr rDrrr&s zProcess.usernameFcs"tt||}tdd|DS)zjThe collection of process's children. Each of them casted from ``psutil.Process`` to tracer ``Process``.cSsg|]}t|jqSr)rr).0childrrr z$Process.children..)rArr1r)rr2r1rDrrr1szProcess.childrencsBtt|}|dr$|dd}d|vr>|d|d}|S)zcThe absolute path to process executable. Cleaned from arbitrary strings which appears on the end.z#newr;)rArr#endswithindex)rr#rDrrr#s   z Process.execCs |dvS)N)Zpython)r"r rrris_interpretedszProcess.is_interpretedcCs8|}|durdS|}|dus0||kr4dSdS)NT)terminalr0)rrmr0rrr is_session s zProcess.is_sessioncCs@|jr8|ddD] }tj|rtj|Sq|Sr[)rlr$r^r]isfilebasenamer")rrbrrr real_names  zProcess.real_namecCstjt}tj|}||}d}|jdkrFt|jd}n`|jdkrhtt|jdd}n>|jdkrtt|jdd}n|jdkrtt|jd}|S) z The time of how long process is running. Returned as string in format ``XX unit`` where unit is one of ``days`` | ``hours`` | ``minutes`` | ``seconds`` rz daysiz hours<z minutesz seconds)datetimeZ fromtimestamptimer'ZdaysstrZsecondsint)rZnowstartedZ started_strrrrstr_started_agos    zProcess.str_started_ago)rQ)F)rrrr;rMrNrPrrZpropertyrar0r&r1r#rlrnrqryrJrrrDrrs*      rc@s&eZdZdZdZdddZddZdS)AffectedProcessNcCs t||t|_t|_dSr )rrsetpackagesrarrrrr9s zAffectedProcess.__init__cCs$|j|j|_|j|j|_dSr )raunionr}rKrrrupdate>szAffectedProcess.update)N)rrrr}rarrrrrrr{5s r{) collectionsrrr rtrur^ subprocessrr threadingrZsixrobjectr rtyper<rr{rrrrs    Vresources/__pycache__/processes.cpython-39.pyc000064400000024541151114232410015425 0ustar00a "eq#@sddlmZddlmZddlZddlZddlZddlZddlmZm Z ddl m Z ddl m Z Gdd d eZGd d d eZGd d d eZGddde eeZGdddeZdS))ProcessesCollection)FilenameCleanerN)PIPEPopen)Timer)with_metaclassc@s$eZdZeddZeddZdS) ProcessescCs*z tWSty$tYS0dSN)psutilpidsAttributeErrorZ get_pid_listrr>/usr/lib/python3.9/site-packages/tracer/resources/processes.pyr !s  zProcesses.pidsc CsRt}tD]>}z|t|Wqtjy8YqtjyJYq0q|Sr )rr r appendProcessr Z NoSuchProcess AccessDenied)Z processespidrrrall(s z Processes.allN)__name__ __module__ __qualname__ staticmethodr rrrrrr s r c@seZdZdZd!ddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ d"ddZddZddZd#dd ZdS)$ProcessWrappera Wrapper for ``psutil.Process class`` Library ``psutil`` is not backward compatible from version 2.x.x to 1.x.x. Purpose of this class is cover incompatibility in ``psutil.Process`` class and provide interface of new version. It allows using new interface even with old version of ``psutil``. Note that, for performance reasons, process information is cached at object creation. To force a refresh, invoke the ``rebuild_cache()`` method. NcCst||_|dSr )r r_process rebuild_cacheselfrrrr__init__As zProcessWrapper.__init__cCs t|jSr )boolrrrrr __nonzero__EszProcessWrapper.__nonzero__cCs|jjgdd|_dS)N)nameexecmdlineppidusername create_time)attrs)rZas_dict _procdictr rrrrHszProcessWrapper.rebuild_cachecCs|z\|ddkrZ|d|dvrZt|ddkrZ|dddd}d|WSWntjypYn0|dS) Nr"Zsshdr#r$r@rzssh-{0}-session)_attrlensplitformatr r)rr&rrrr"Ks&zProcessWrapper.namecCs |dS)Nr#r+r rrrr#WszProcessWrapper.execCs |dS)Nr$r/r rrrr$ZszProcessWrapper.cmdlinecCs |dS)Nr%r/r rrrr%]szProcessWrapper.ppidcCs |dS)Nparentr/r rrrr0`szProcessWrapper.parentcCs |dS)Nr&r/r rrrr&cszProcessWrapper.usernamecCs |dS)Nr'r/r rrrr'fszProcessWrapper.create_timeFcCsZd|}||jvrPz|j||j|<Wn$tyN|j||j|<Yn0|j|S)Nz children-{0})r.r)rchildrenr Z get_children)r recursivekeyrrrr1is   zProcessWrapper.childrencCsN||jvrDt|j|}z||j|<WntyB||j|<Yn0|j|Sr )r)getattrr TypeError)rr"attrrrrr+rs   zProcessWrapper._attrcCs t|j|Sr )r4r)ritemrrr __getattr__{szProcessWrapper.__getattr__TcCs^d|}||jvrTz|jj|d|j|<Wn&tyR|jj|d|j|<Yn0|j|S)Nzmemory_maps-{0})grouped)r.r)r memory_mapsr Zget_memory_maps)rr9r3rrrr:s   zProcessWrapper.memory_maps)N)F)T)rrr__doc__rr!rr"r#r$r%r0r&r'r1r+r8r:rrrrr3s    rcs(eZdZdZfddZddZZS) ProcessMetaz Caching metaclass that ensures that only one ``Process`` object is ever instantiated for any given PID. The cache can be cleared by calling ``Process.reset_cache()``. Based on https://stackoverflow.com/a/33458129 cs6tt|||fdd}|td|dS)Ncs i_dSr )_cacherclsrr reset_cachesz)ProcessMeta.__init__..reset_cacher@)superr<rsetattr)r?r"basesZ attributesr@ __class__r>rrs zProcessMeta.__init__cOsV|d}||jvrL|j|g|Ri|}|j|g|Ri|||j|<|j|S)Nr)r=__new__r)r?argskwargsrrrrr__call__s   zProcessMeta.__call__)rrrr;rrI __classcell__rrrDrr<s r<cseZdZdZddZddZddZedd d Ze d d Z d dZ fddZ dfdd Z e fddZe ddZe ddZe ddZe ddZZS) raS Represent the process instance uniquely identifiable through PID For all class properties and methods, please see http://pythonhosted.org/psutil/#process-class Below listed are only reimplemented ones. For performance reasons, instances are cached based on PID, and multiple instantiations of a ``Process`` object with the same PID will return the same object. To clear the cache, invoke ``Process.reset_cache()``. Additionally, as with ``ProcessWrapper``, process information is cached at object creation. To force a refresh, invoke the ``rebuild_cache()`` method on the object. cCs |j|jkS)zBFor our purposes, two processes are equal when they have same name)rrprocessrrr__eq__szProcess.__eq__cCs || Sr )rMrKrrr__ne__szProcess.__ne__cCs t|jSr )hashrr rrr__hash__szProcess.__hash__?cCsTtdd|gttd}t||j}z$|||jdkW|S|0dS)z Process arguments could be referring to files on remote filesystems and os.path.isfile will hang forever if the shared FS is offline. Instead, use a subprocess that we can time out if we can't reach some file. testz-f)stdoutstderrrN)rrrkillstartZ communicate returncodecancel)Z file_pathtimeoutrLZtimerrrr safe_isfiles  zProcess.safe_isfilecCsdg}|D]}|t|jq |ddD]&}tj|sFq4t |r4||q4t |SNr) r:rrstrippathr$osisabsrrZsorted)rfilesZmmapargrrrras    z Process.filescCs|rt|SdS)zGThe parent process casted from ``psutil.Process`` to tracer ``Process``N)r%rr rrrr0s zProcess.parentcs*ztt|WSty$YdS0dS)zcThe user who owns the process. If user was deleted in the meantime, ``None`` is returned instead.N)rArr&KeyErrorr rDrrr&s zProcess.usernameFcs"tt||}tdd|DS)zjThe collection of process's children. Each of them casted from ``psutil.Process`` to tracer ``Process``.cSsg|]}t|jqSr)rr).0childrrr z$Process.children..)rArr1r)rr2r1rDrrr1szProcess.childrencsBtt|}|dr$|dd}d|vr>|d|d}|S)zcThe absolute path to process executable. Cleaned from arbitrary strings which appears on the end.z#newr;)rArr#endswithindex)rr#rDrrr#s   z Process.execCs |dvS)N)Zpython)r"r rrris_interpretedszProcess.is_interpretedcCs8|}|durdS|}|dus0||kr4dSdS)NT)terminalr0)rrmr0rrr is_session s zProcess.is_sessioncCs@|jr8|ddD] }tj|rtj|Sq|Sr[)rlr$r^r]isfilebasenamer")rrbrrr real_names  zProcess.real_namecCstjt}tj|}||}d}|jdkrFt|jd}n`|jdkrhtt|jdd}n>|jdkrtt|jdd}n|jdkrtt|jd}|S) z The time of how long process is running. Returned as string in format ``XX unit`` where unit is one of ``days`` | ``hours`` | ``minutes`` | ``seconds`` rz daysiz hours<z minutesz seconds)datetimeZ fromtimestamptimer'ZdaysstrZsecondsint)rZnowstartedZ started_strrrrstr_started_agos    zProcess.str_started_ago)rQ)F)rrrr;rMrNrPrrZpropertyrar0r&r1r#rlrnrqryrJrrrDrrs*      rc@s&eZdZdZdZdddZddZdS)AffectedProcessNcCs t||t|_t|_dSr )rrsetpackagesrarrrrr9s zAffectedProcess.__init__cCs$|j|j|_|j|j|_dSr )raunionr}rKrrrupdate>szAffectedProcess.update)N)rrrr}rarrrrrrr{5s r{) collectionsrrr rtrur^ subprocessrr threadingrZsixrobjectr rtyper<rr{rrrrs    Vresources/__pycache__/pycomp.cpython-39.opt-1.pyc000064400000001554151114232410015664 0ustar00a "e@sXddlmZejdkZer4ddlmZddlmZnddlmZddlmZddZ dS)) version_info)StringIO) lru_cachecCsLtsddl}|||Sddlm}ddl}|||}||j}||S)z Read and evaluate a python file This is useful when we don't know the module name beforehand and somehow figure it out at the runtime (e.g. user-defined hook files) rN)SourceFileLoader) PY3imp load_sourceZimportlib.machineryrtypes ModuleTypename exec_module)Z module_namepathrrr loaderZloadedr;/usr/lib/python3.9/site-packages/tracer/resources/pycomp.pyr s    r N) sysrmajorrior functoolsrZbackports.functools_lru_cacher rrrrs     resources/__pycache__/pycomp.cpython-39.pyc000064400000001554151114232410014725 0ustar00a "e@sXddlmZejdkZer4ddlmZddlmZnddlmZddlmZddZ dS)) version_info)StringIO) lru_cachecCsLtsddl}|||Sddlm}ddl}|||}||j}||S)z Read and evaluate a python file This is useful when we don't know the module name beforehand and somehow figure it out at the runtime (e.g. user-defined hook files) rN)SourceFileLoader) PY3imp load_sourceZimportlib.machineryrtypes ModuleTypename exec_module)Z module_namepathrrr loaderZloadedr;/usr/lib/python3.9/site-packages/tracer/resources/pycomp.pyr s    r N) sysrmajorrior functoolsrZbackports.functools_lru_cacher rrrrs     resources/__pycache__/router.cpython-39.opt-1.pyc000064400000002362151114232410015673 0ustar00a "e%@s>ddlmZddlZddlmZddlmZGdddZdS))absolute_importN) __version__)_c@s$eZdZdZdZddZddZdS)RouterNcCs||_||_dS)N)argspackages)selfrrr ;/usr/lib/python3.9/site-packages/tracer/resources/router.py__init__ szRouter.__init__cCs|jjr,ddlm}||j|j}|n|jjr>ttnn|jj rfddl m }||j}|nFddl m }||j|j}|jjr|n|jjr|n|dS)Nr)HelperController)ResourceController)DefaultController)rhelperZtracer.controllers.helperr rZrenderversionprintrresourceZtracer.controllers.resourcer Ztracer.controllers.defaultrZhelpersZrender_helpers interactiveZrender_interactive)rr Z controllerr rr r r dispatch$s"         zRouter.dispatch)__name__ __module__ __qualname__rrr rr r r r rsr)Z __future__rosZtracer.versionrZtracer.resources.langrrr r r r s   resources/__pycache__/router.cpython-39.pyc000064400000002362151114232410014734 0ustar00a "e%@s>ddlmZddlZddlmZddlmZGdddZdS))absolute_importN) __version__)_c@s$eZdZdZdZddZddZdS)RouterNcCs||_||_dS)N)argspackages)selfrrr ;/usr/lib/python3.9/site-packages/tracer/resources/router.py__init__ szRouter.__init__cCs|jjr,ddlm}||j|j}|n|jjr>ttnn|jj rfddl m }||j}|nFddl m }||j|j}|jjr|n|jjr|n|dS)Nr)HelperController)ResourceController)DefaultController)rhelperZtracer.controllers.helperr rZrenderversionprintrresourceZtracer.controllers.resourcer Ztracer.controllers.defaultrZhelpersZrender_helpers interactiveZrender_interactive)rr Z controllerr rr r r dispatch$s"         zRouter.dispatch)__name__ __module__ __qualname__rrr rr r r r rsr)Z __future__rosZtracer.versionrZtracer.resources.langrrr r r r s   resources/__pycache__/rules.cpython-39.opt-1.pyc000064400000007523151114232410015511 0ustar00a "e @stddlmZddlmZddlmZddlmZmZddl m Z m Z ddl m Z GdddeZGd d d eZd S) )absolute_import)minidom) ExpatError)DATA_DIRUSER_CONFIG_DIRS) PathNotFound TracerError)dirnamec@sfeZdZeddegeZdddZedZdZ e dd Z e d d Z e d d Z e ddZdS)RulescCs|dS)Nz /rules.xml)xr r :/usr/lib/python3.9/site-packages/tracer/resources/rules.pyzRules.z call-parentreturn) CALL-PARENTZRETURNrNcCs0tjsttjD]}|j|kr|SqdSN)r _rules_load_definitionsname)Zapp_nameruler r r find's   z Rules.findcCstjsttjSr)r rrr r r r all0sz Rules.allc CsZgt_tjD]H}zt|Wq tyR}zt|tvr>|WYd}~q d}~00q dSr)r r DEFINITIONS_loadrr r)fileexr r r r7s   zRules._load_definitionsc Cs zr r r __contains__tszRule.__contains__cCsd|jddS)Nzr5rBr r r __str__wsz Rule.__str__cCs|Sr)rFrBr r r __repr__zsz Rule.__repr__cCs|j||dSr)r6r))r7keyvaluer r r r)}szRule.setdefaultcCs t|tr|j}|j|dSr)r9r&r6r()r7valuesr r r r(s z Rule.update)r0r1r2__doc__r6r8r<r=r@rCrDrFrGr)r(r r r r r&Ws r&N)Z __future__rZxml.domrZxml.parsers.expatrZ tracer.pathsrrZtracer.resources.exceptionsrrZos.pathr objectr r&r r r r s    ;resources/__pycache__/rules.cpython-39.pyc000064400000007523151114232410014552 0ustar00a "e @stddlmZddlmZddlmZddlmZmZddl m Z m Z ddl m Z GdddeZGd d d eZd S) )absolute_import)minidom) ExpatError)DATA_DIRUSER_CONFIG_DIRS) PathNotFound TracerError)dirnamec@sfeZdZeddegeZdddZedZdZ e dd Z e d d Z e d d Z e ddZdS)RulescCs|dS)Nz /rules.xml)xr r :/usr/lib/python3.9/site-packages/tracer/resources/rules.pyzRules.z call-parentreturn) CALL-PARENTZRETURNrNcCs0tjsttjD]}|j|kr|SqdSN)r _rules_load_definitionsname)Zapp_nameruler r r find's   z Rules.findcCstjsttjSr)r rrr r r r all0sz Rules.allc CsZgt_tjD]H}zt|Wq tyR}zt|tvr>|WYd}~q d}~00q dSr)r r DEFINITIONS_loadrr r)fileexr r r r7s   zRules._load_definitionsc Cs zr r r __contains__tszRule.__contains__cCsd|jddS)Nzr5rBr r r __str__wsz Rule.__str__cCs|Sr)rFrBr r r __repr__zsz Rule.__repr__cCs|j||dSr)r6r))r7keyvaluer r r r)}szRule.setdefaultcCs t|tr|j}|j|dSr)r9r&r6r()r7valuesr r r r(s z Rule.update)r0r1r2__doc__r6r8r<r=r@rCrDrFrGr)r(r r r r r&Ws r&N)Z __future__rZxml.domrZxml.parsers.expatrZ tracer.pathsrrZtracer.resources.exceptionsrrZos.pathr objectr r&r r r r s    ;resources/__pycache__/system.cpython-39.opt-1.pyc000064400000007447151114232410015710 0ustar00a "e@slddlmZddlZddlZddlZddlZddlZddlmZddl m Z ddl m Z Gddde ZdS))absolute_importN) version_info)PackageManager)Processc@sleZdZeddZeddZeddZeddZed d Zed d Z ed dZ eddZ dS)SystemcCstjdrtd}i}gd}dd|D}|D] }|d\}}|d||<q4|d|vr|ddkr|d d krWd d S|dWd Sd |vr|d D]"}||vr|Wd SqWd n1s0YntSd S)z Checks if /etc/os-release exists, and if it does, uses it to divine the name of the distribution or distribution like. e.g It will return 'debian' on Ubuntu systems. Otherwise, revert to using distro.id() z/etc/os-release) gentoodebianrhelcentosolmageiaarcharcharmfedorasusecSsg|]}|r|qS)rstrip).0linerr;/usr/lib/python3.9/site-packages/tracer/resources/system.py 0z'System.distribution..="ZIDr Z VERSION_IDNcentos-7ZID_LIKE)ospathisfileopensplitstripdistroid)Zos_release_fileZos_release_dataZdistroslinesrZos_release_keyZos_release_value distributionrrrr%#s"   8zSystem.distributionc spfdd}dgdgddgddgdgddgdgdgdgddgdgd }t}||vrZd Sttt|||S) zMReturns instance of package manager according to installed linux distributioncs&|\}}t|}t||fiSN) importlib import_modulegetattr)Zpairrnamemodulekwargsrr get_instanceEs z,System.package_manager..get_instance)ztracer.packageManagers.portageZPortage)ztracer.packageManagers.dpkgZDpkg)ztracer.packageManagers.dnfZDnf)ztracer.packageManagers.yumZYum)ztracer.packageManagers.alpmZAlpm) rrr r rr r r rrrN)rr%rlistmap)r-r.Zmanagersr%rr,rpackage_managerAs2 zSystem.package_managercCstd}|dd}|S)zM Returns name of init system you are using e.g. init, systemd, upstart  r)rr*r )initr*rrr init_systemkszSystem.init_systemcCs*z tWSty$tYS0dSr&)psutil boot_timeAttributeErrorZ get_boot_timerrrrr7vs zSystem.boot_timecCsdtjtjtjS)Nz{}.{}.{})formatrmajorminormicrorrrrpython_version|szSystem.python_versioncCstttdS)N)rr1Z find_packagekernel_package_namerunamerrrrrunning_kernel_packageszSystem.running_kernel_packagecCsdS)z6 TODO: infer kernel package from current distribution Zkernelrrrrrr?szSystem.kernel_package_namecCs4z tWSty.ttdYS0dS)Nr)rgetloginOSErrorpwdgetpwuidgetuidrrrrusers z System.userN) __name__ __module__ __qualname__ staticmethodr%r1r5r7r=rAr?rGrrrrr!s   )     r)Z __future__rrrDr'r"r6sysrZtracer.resources.PackageManagerrZtracer.resources.processesrobjectrrrrrs    resources/__pycache__/system.cpython-39.pyc000064400000007447151114232410014751 0ustar00a "e@slddlmZddlZddlZddlZddlZddlZddlmZddl m Z ddl m Z Gddde ZdS))absolute_importN) version_info)PackageManager)Processc@sleZdZeddZeddZeddZeddZed d Zed d Z ed dZ eddZ dS)SystemcCstjdrtd}i}gd}dd|D}|D] }|d\}}|d||<q4|d|vr|ddkr|d d krWd d S|dWd Sd |vr|d D]"}||vr|Wd SqWd n1s0YntSd S)z Checks if /etc/os-release exists, and if it does, uses it to divine the name of the distribution or distribution like. e.g It will return 'debian' on Ubuntu systems. Otherwise, revert to using distro.id() z/etc/os-release) gentoodebianrhelcentosolmageiaarcharcharmfedorasusecSsg|]}|r|qS)rstrip).0linerr;/usr/lib/python3.9/site-packages/tracer/resources/system.py 0z'System.distribution..="ZIDr Z VERSION_IDNcentos-7ZID_LIKE)ospathisfileopensplitstripdistroid)Zos_release_fileZos_release_dataZdistroslinesrZos_release_keyZos_release_value distributionrrrr%#s"   8zSystem.distributionc spfdd}dgdgddgddgdgddgdgdgdgddgdgd }t}||vrZd Sttt|||S) zMReturns instance of package manager according to installed linux distributioncs&|\}}t|}t||fiSN) importlib import_modulegetattr)Zpairrnamemodulekwargsrr get_instanceEs z,System.package_manager..get_instance)ztracer.packageManagers.portageZPortage)ztracer.packageManagers.dpkgZDpkg)ztracer.packageManagers.dnfZDnf)ztracer.packageManagers.yumZYum)ztracer.packageManagers.alpmZAlpm) rrr r rr r r rrrN)rr%rlistmap)r-r.Zmanagersr%rr,rpackage_managerAs2 zSystem.package_managercCstd}|dd}|S)zM Returns name of init system you are using e.g. init, systemd, upstart  r)rr*r )initr*rrr init_systemkszSystem.init_systemcCs*z tWSty$tYS0dSr&)psutil boot_timeAttributeErrorZ get_boot_timerrrrr7vs zSystem.boot_timecCsdtjtjtjS)Nz{}.{}.{})formatrmajorminormicrorrrrpython_version|szSystem.python_versioncCstttdS)N)rr1Z find_packagekernel_package_namerunamerrrrrunning_kernel_packageszSystem.running_kernel_packagecCsdS)z6 TODO: infer kernel package from current distribution Zkernelrrrrrr?szSystem.kernel_package_namecCs4z tWSty.ttdYS0dS)Nr)rgetloginOSErrorpwdgetpwuidgetuidrrrrusers z System.userN) __name__ __module__ __qualname__ staticmethodr%r1r5r7r=rAr?rGrrrrr!s   )     r)Z __future__rrrDr'r"r6sysrZtracer.resources.PackageManagerrZtracer.resources.processesrobjectrrrrrs    resources/__pycache__/tracer.cpython-39.opt-1.pyc000064400000012000151114232410015621 0ustar00a "e@sddlmZddlZddlmZddlmZddlmZddl m Z ddl m Z ddl mZmZmZdd lmZdd lmZmZdd lmZGd d d eZdS))absolute_importN) NoSuchProcess)Package)System)FilenameCleaner)AffectedProcess)ApplicationsCollectionAffectedProcessesCollectionPackagesCollection)UnsupportedDistribution) ApplicationsAffectedApplication)_c@seZdZdZdZdZdZdZdZdZ dZ dZ dZ dddZ ddZddd Zd d Zd d ZddZefddZefddZddZdS)Tracerz9Tracer finds outdated running applications in your systemNFcCs8|stt||_||_||_||_||_||_dSN) r rZ distribution_PACKAGE_MANAGER_rules _applications_memory_hooks_observer_erased)selfZpackage_managerZrulesZ applicationsmemoryZhooks_observerZerasedr;/usr/lib/python3.9/site-packages/tracer/resources/tracer.py__init__Bs zTracer.__init__cCsF|jr|jrt|jS|jr"|jnt}|j|}||j}|S)z6Returns list of packages what tracer should care about) specified_packagesnowr timestamprZ boot_timerZpackages_newer_than intersection)rrpackagesrrr_modified_packagesMs     zTracer._modified_packagesc Csp||}|}i}g}|D]}|j|jD]}t|}||vrNq6||D]}|j|vrfqVz| |j kr| |j| |}|j |} | js| j|vr|jr|j| stjd| _t| j|| j<t|| j_||| j|| jj |WqVty$YqV0qVq6q"|j djsd|rdtdtjdtdd|d<t|S)z Returns collection of applications which uses some files that have been modified @TODO This function should be hardly optimized ZERASEDZkernelZSTATICz%You will have to reboot your computer)nametypehelper)rr!Z unique_newestr package_filesr"rstrippid create_timemodifiedappend _apply_rulesrfindignorerZ provided_byr ZTYPESr#r _attributesr Zaffected_instances _call_hookr_has_updated_kernelrrvalues) ruserrr affectedfoundpackagefileparrrtrace_affectedWs@           zTracer.trace_affectedcCsBt}|durdSt}t|}||j|j||dkS)NF)rZrunning_kernel_packagekernel_package_namerZ load_inforZcompare_packages)rZrunningr;Zlatestrrrr0s zTracer._has_updated_kernelcCsx|}|s|S|j|}|j|}|rJ|j|jjdkrJ|S|rT|jsX|S|j|jjdkrt||S|S)NZRETURNz CALL-PARENT)parentrr,r"actionZACTIONSr+)rprocessr<Zc_ruleZp_rulerrrr+s  zTracer._apply_rulescCs|jr||jdSr)rr")rapprrrr/szTracer._call_hookcCsF|}t}|jD],}||||||||||q|S)z Returns collection of processes where each of them contains packages which affected it. Packages contains only files matching with the particular process )r!r Z instancesupdate_affecting_processes_affecting_children)rr?affected_process_factoryr processesr>rrrtrace_applications  zTracer.trace_applicationc Cst}|j}|D]}t}|j|jD]0}t|}||vr@q(||j kr(| |q(|r|} || _||j } | j |j | j | g| | gq|Sr)r filessetrr%r"rr&r(r)addr'__dict__r@r ) rr>r rCZ collectionZ process_filesr5Zmatching_filesZ package_fileZaff_pkgr3rrrrAs$   zTracer._affecting_processescCsT|j|siSt}|D],}||||||||||q"|Sr)rr,r"r Zchildrenr@rArB)rr>r rCrDchildrrrrBs zTracer._affecting_children)NNF)N)__name__ __module__ __qualname____doc__rrrrrrrrrrr!r9r0r+r/rrErArBrrrrr!s&  .  r)Z __future__rosZpsutilrZtracer.resources.packagerZtracer.resources.systemrZ tracer.resources.FilenameCleanerrZtracer.resources.processesrZtracer.resources.collectionsrr r Ztracer.resources.exceptionsr Ztracer.resources.applicationsr r Ztracer.resources.langrobjectrrrrrs        resources/__pycache__/tracer.cpython-39.pyc000064400000012000151114232410014662 0ustar00a "e@sddlmZddlZddlmZddlmZddlmZddl m Z ddl m Z ddl mZmZmZdd lmZdd lmZmZdd lmZGd d d eZdS))absolute_importN) NoSuchProcess)Package)System)FilenameCleaner)AffectedProcess)ApplicationsCollectionAffectedProcessesCollectionPackagesCollection)UnsupportedDistribution) ApplicationsAffectedApplication)_c@seZdZdZdZdZdZdZdZdZ dZ dZ dZ dddZ ddZddd Zd d Zd d ZddZefddZefddZddZdS)Tracerz9Tracer finds outdated running applications in your systemNFcCs8|stt||_||_||_||_||_||_dSN) r rZ distribution_PACKAGE_MANAGER_rules _applications_memory_hooks_observer_erased)selfZpackage_managerZrulesZ applicationsmemoryZhooks_observerZerasedr;/usr/lib/python3.9/site-packages/tracer/resources/tracer.py__init__Bs zTracer.__init__cCsF|jr|jrt|jS|jr"|jnt}|j|}||j}|S)z6Returns list of packages what tracer should care about) specified_packagesnowr timestamprZ boot_timerZpackages_newer_than intersection)rrpackagesrrr_modified_packagesMs     zTracer._modified_packagesc Csp||}|}i}g}|D]}|j|jD]}t|}||vrNq6||D]}|j|vrfqVz| |j kr| |j| |}|j |} | js| j|vr|jr|j| stjd| _t| j|| j<t|| j_||| j|| jj |WqVty$YqV0qVq6q"|j djsd|rdtdtjdtdd|d<t|S)z Returns collection of applications which uses some files that have been modified @TODO This function should be hardly optimized ZERASEDZkernelZSTATICz%You will have to reboot your computer)nametypehelper)rr!Z unique_newestr package_filesr"rstrippid create_timemodifiedappend _apply_rulesrfindignorerZ provided_byr ZTYPESr#r _attributesr Zaffected_instances _call_hookr_has_updated_kernelrrvalues) ruserrr affectedfoundpackagefileparrrtrace_affectedWs@           zTracer.trace_affectedcCsBt}|durdSt}t|}||j|j||dkS)NF)rZrunning_kernel_packagekernel_package_namerZ load_inforZcompare_packages)rZrunningr;Zlatestrrrr0s zTracer._has_updated_kernelcCsx|}|s|S|j|}|j|}|rJ|j|jjdkrJ|S|rT|jsX|S|j|jjdkrt||S|S)NZRETURNz CALL-PARENT)parentrr,r"actionZACTIONSr+)rprocessr<Zc_ruleZp_rulerrrr+s  zTracer._apply_rulescCs|jr||jdSr)rr")rapprrrr/szTracer._call_hookcCsF|}t}|jD],}||||||||||q|S)z Returns collection of processes where each of them contains packages which affected it. Packages contains only files matching with the particular process )r!r Z instancesupdate_affecting_processes_affecting_children)rr?affected_process_factoryr processesr>rrrtrace_applications  zTracer.trace_applicationc Cst}|j}|D]}t}|j|jD]0}t|}||vr@q(||j kr(| |q(|r|} || _||j } | j |j | j | g| | gq|Sr)r filessetrr%r"rr&r(r)addr'__dict__r@r ) rr>r rCZ collectionZ process_filesr5Zmatching_filesZ package_fileZaff_pkgr3rrrrAs$   zTracer._affecting_processescCsT|j|siSt}|D],}||||||||||q"|Sr)rr,r"r Zchildrenr@rArB)rr>r rCrDchildrrrrBs zTracer._affecting_children)NNF)N)__name__ __module__ __qualname____doc__rrrrrrrrrrr!r9r0r+r/rrErArBrrrrr!s&  .  r)Z __future__rosZpsutilrZtracer.resources.packagerZtracer.resources.systemrZ tracer.resources.FilenameCleanerrZtracer.resources.processesrZtracer.resources.collectionsrr r Ztracer.resources.exceptionsr Ztracer.resources.applicationsr r Ztracer.resources.langrobjectrrrrrs        resources/__pycache__/FilenameCleaner.cpython-39.opt-1.pyc000064400000003755151114232410017374 0ustar00a "e @sGdddeZdS)c@sHeZdZeddZeddZeddZeddZed d Zd S) FilenameCleanercCst|}zP|d}|d|}||dd}d|vrNt|}t|}|d|WStylYnty|Yn0|S)N/.)r_strip_abnormalitiesrindex_strip_around_so_delimited_dots_strip_after_dash IndexError ValueError)filenameZslashdirnamebasenamerD/usr/lib/python3.9/site-packages/tracer/resources/FilenameCleaner.pystrips     zFilenameCleaner.stripcCsxz|d|d}Wnty(Yn0|dr@|dd}d|vrZ|d|d}d|vrt|d|d}|S)N z#new;z .#prelink#.)indexr endswithr)r rrrr/s  z$FilenameCleaner._strip_abnormalitiescCs~zV|d}|d}t|dkr(|d7}|d}|d}|d|||d}Wn"tyhYntyxYn0|S)Nz.sorrr)splitlenrrr r )r rZ first_dot_iZ last_dot_irrrrFs    z/FilenameCleaner._strip_around_so_delimited_dotscCspzH|d}|d|}t||d|rF|d|||d}Wn"tyZYntyjYn0|S)N-rr)rrr _is_versionr r )r ZdashdotrrrrUs  z!FilenameCleaner._strip_after_dashcCs$|D]}|r|dkrdSqdS)z: Returns True if string contains only digits and dots rFT)isdigit)stringcharrrrraszFilenameCleaner._is_versionN) __name__ __module__ __qualname__ staticmethodrrrrrrrrrrs    rN)objectrrrrrresources/__pycache__/FilenameCleaner.cpython-39.pyc000064400000003755151114232410016435 0ustar00a "e @sGdddeZdS)c@sHeZdZeddZeddZeddZeddZed d Zd S) FilenameCleanercCst|}zP|d}|d|}||dd}d|vrNt|}t|}|d|WStylYnty|Yn0|S)N/.)r_strip_abnormalitiesrindex_strip_around_so_delimited_dots_strip_after_dash IndexError ValueError)filenameZslashdirnamebasenamerD/usr/lib/python3.9/site-packages/tracer/resources/FilenameCleaner.pystrips     zFilenameCleaner.stripcCsxz|d|d}Wnty(Yn0|dr@|dd}d|vrZ|d|d}d|vrt|d|d}|S)N z#new;z .#prelink#.)indexr endswithr)r rrrr/s  z$FilenameCleaner._strip_abnormalitiescCs~zV|d}|d}t|dkr(|d7}|d}|d}|d|||d}Wn"tyhYntyxYn0|S)Nz.sorrr)splitlenrrr r )r rZ first_dot_iZ last_dot_irrrrFs    z/FilenameCleaner._strip_around_so_delimited_dotscCspzH|d}|d|}t||d|rF|d|||d}Wn"tyZYntyjYn0|S)N-rr)rrr _is_versionr r )r ZdashdotrrrrUs  z!FilenameCleaner._strip_after_dashcCs$|D]}|r|dkrdSqdS)z: Returns True if string contains only digits and dots rFT)isdigit)stringcharrrrraszFilenameCleaner._is_versionN) __name__ __module__ __qualname__ staticmethodrrrrrrrrrrs    rN)objectrrrrrresources/__pycache__/PackageManager.cpython-39.opt-1.pyc000064400000005611151114232410017201 0ustar00a "e @s&ddlmZddlZGdddZdS))absolute_importNc@sTeZdZdZdZddZddZddZd d Zd d Z d dZ ddZ ddZ dS)PackageManagerz Wrapper class for package managers. Provides their API and allows to use multiple package managers at once. In actions where it makes no sense to merge results from more package managers, result from first manager is used. NcGs ||_dSN)package_managers)selfZ instancesrC/usr/lib/python3.9/site-packages/tracer/resources/PackageManager.py__init__%szPackageManager.__init__cCstdd|jS)NcSs|jjSr) __class____name__)xrrr)z&PackageManager.names..)mapr)rrrrnames(szPackageManager.namescs0ddlm}fdd|jD}|tj|S)z Returns list of packages which were modified between unix_time and present Packages in list should be dictionaries with keys {"name", "modified"} r)PackagesCollectioncsg|]}|qSr)packages_newer_than).0p unix_timerr 2rz6PackageManager.packages_newer_than..)Ztracer.resources.collectionsrr itertoolschain from_iterable)rrrZpackages_listsrrrr+s z"PackageManager.packages_newer_thancCs|jd|S)z)Returns list of files provided by packager)r package_files)rpkg_namerrrr5szPackageManager.package_filescCs|jd|S)zFFrom database load informations about given package and set them to itr)rload_package_info)rpackagerrrr9sz PackageManager.load_package_infocCs|jd|S)z8Returns name of package which provides given applicationr)r provided_by)rZapprrrr=szPackageManager.provided_bycCs|jd||S)z4Find a package by name and some other input criteriar)r find_package)rrsearchrrrr AszPackageManager.find_packagecCs|jd||S)z Compares two packages by their version information Returns: 0 if they are equal 1 if package1 > package2 -1 if package2 > package1 r)rcompare_packages)rZpackage1Zpackage2rrrr"EszPackageManager.compare_packages) r __module__ __qualname____doc__rr rrrrrr r"rrrrrs r)Z __future__rrrrrrrs resources/__pycache__/PackageManager.cpython-39.pyc000064400000005611151114232410016242 0ustar00a "e @s&ddlmZddlZGdddZdS))absolute_importNc@sTeZdZdZdZddZddZddZd d Zd d Z d dZ ddZ ddZ dS)PackageManagerz Wrapper class for package managers. Provides their API and allows to use multiple package managers at once. In actions where it makes no sense to merge results from more package managers, result from first manager is used. NcGs ||_dSN)package_managers)selfZ instancesrC/usr/lib/python3.9/site-packages/tracer/resources/PackageManager.py__init__%szPackageManager.__init__cCstdd|jS)NcSs|jjSr) __class____name__)xrrr)z&PackageManager.names..)mapr)rrrrnames(szPackageManager.namescs0ddlm}fdd|jD}|tj|S)z Returns list of packages which were modified between unix_time and present Packages in list should be dictionaries with keys {"name", "modified"} r)PackagesCollectioncsg|]}|qSr)packages_newer_than).0p unix_timerr 2rz6PackageManager.packages_newer_than..)Ztracer.resources.collectionsrr itertoolschain from_iterable)rrrZpackages_listsrrrr+s z"PackageManager.packages_newer_thancCs|jd|S)z)Returns list of files provided by packager)r package_files)rpkg_namerrrr5szPackageManager.package_filescCs|jd|S)zFFrom database load informations about given package and set them to itr)rload_package_info)rpackagerrrr9sz PackageManager.load_package_infocCs|jd|S)z8Returns name of package which provides given applicationr)r provided_by)rZapprrrr=szPackageManager.provided_bycCs|jd||S)z4Find a package by name and some other input criteriar)r find_package)rrsearchrrrr AszPackageManager.find_packagecCs|jd||S)z Compares two packages by their version information Returns: 0 if they are equal 1 if package1 > package2 -1 if package2 > package1 r)rcompare_packages)rZpackage1Zpackage2rrrr"EszPackageManager.compare_packages) r __module__ __qualname____doc__rr rrrrrr r"rrrrrs r)Z __future__rrrrrrrs resources/__pycache__/SystemdDbus.cpython-39.opt-1.pyc000064400000003535151114232410016624 0ustar00a "e.@sddlZGdddeZdS)Nc@s4eZdZddZddZddZddZd d Zd S) SystemdDbuscCs(tdd|_tj|jdd|_dS)Norg.freedesktop.systemd1z/org/freedesktop/systemd1z org.freedesktop.systemd1.ManagerZdbus_interface)dbus SystemBus get_objectZ_SystemdDbus__systemdZ Interface_SystemdDbus__manager)selfr @/usr/lib/python3.9/site-packages/tracer/resources/SystemdDbus.py__init__szSystemdDbus.__init__cCs,z|j|WStjjy&YdS0dSNF)rZ GetUnitByPIDr exceptions DBusException)r pidr r r unit_path_from_pidszSystemdDbus.unit_path_from_pidcCs,z|j|WStjjy&YdS0dSr )rZGetUnitrrr)r ZIdr r r unit_path_from_idszSystemdDbus.unit_path_from_idcCsZz8||}|sWdStd|}|jd|dd}WntjjyPYdS0t|S)NFrz org.freedesktop.systemd1.Serviceorg.freedesktop.DBus.Propertiesr)rrrrGetrrbool)r rattrZunitproxyZproptyr r r has_service_property_from_pid%s z)SystemdDbus.has_service_property_from_pidcCs@||}t|r8td||}|jd|ddSdSdS)Nrzorg.freedesktop.systemd1.UnitrrF)rrrrrr)r rrZ unit_pathrr r r get_unit_property_from_pid1s  z&SystemdDbus.get_unit_property_from_pidN)__name__ __module__ __qualname__r rrrrr r r r rs  r)robjectrr r r r sresources/__pycache__/SystemdDbus.cpython-39.pyc000064400000003535151114232410015665 0ustar00a "e.@sddlZGdddeZdS)Nc@s4eZdZddZddZddZddZd d Zd S) SystemdDbuscCs(tdd|_tj|jdd|_dS)Norg.freedesktop.systemd1z/org/freedesktop/systemd1z org.freedesktop.systemd1.ManagerZdbus_interface)dbus SystemBus get_objectZ_SystemdDbus__systemdZ Interface_SystemdDbus__manager)selfr @/usr/lib/python3.9/site-packages/tracer/resources/SystemdDbus.py__init__szSystemdDbus.__init__cCs,z|j|WStjjy&YdS0dSNF)rZ GetUnitByPIDr exceptions DBusException)r pidr r r unit_path_from_pidszSystemdDbus.unit_path_from_pidcCs,z|j|WStjjy&YdS0dSr )rZGetUnitrrr)r ZIdr r r unit_path_from_idszSystemdDbus.unit_path_from_idcCsZz8||}|sWdStd|}|jd|dd}WntjjyPYdS0t|S)NFrz org.freedesktop.systemd1.Serviceorg.freedesktop.DBus.Propertiesr)rrrrGetrrbool)r rattrZunitproxyZproptyr r r has_service_property_from_pid%s z)SystemdDbus.has_service_property_from_pidcCs@||}t|r8td||}|jd|ddSdSdS)Nrzorg.freedesktop.systemd1.UnitrrF)rrrrrr)r rrZ unit_pathrr r r get_unit_property_from_pid1s  z&SystemdDbus.get_unit_property_from_pidN)__name__ __module__ __qualname__r rrrrr r r r rs  r)robjectrr r r r sresources/__pycache__/__init__.cpython-39.opt-1.pyc000064400000000230151114232410016102 0ustar00a "e@sdS)Nrrr=/usr/lib/python3.9/site-packages/tracer/resources/__init__.pyresources/__pycache__/__init__.cpython-39.pyc000064400000000230151114232410015143 0ustar00a "e@sdS)Nrrr=/usr/lib/python3.9/site-packages/tracer/resources/__init__.pyresources/__pycache__/applications.cpython-39.opt-1.pyc000064400000023164151114232410017044 0ustar00a "e#@sddlmZddlmZddlmZddlmZmZddl m Z m Z ddl m Z ddlmZddlmZdd lmZdd lmZdd lmZdd lZdd lZGd ddeZGdddZGdddeZd S))absolute_import)minidom) ExpatError)DATA_DIRUSER_CONFIG_DIRS) PathNotFound TracerError)ApplicationsCollection)_) Processes)System) SystemdDbus) lru_cacheNc@seZdZeddegeZddddddd Zed Zd Z e d d Z e ddZ e ddZ eddZeddZe ifddZe ddZd S) ApplicationscCs|dS)Nz/applications.xml)xrrA/usr/lib/python3.9/site-packages/tracer/resources/applications.py%zApplications.daemonZstaticZsession applicationZerasedZ undefined)DAEMONSTATICSESSION APPLICATIONZERASEDUNDEFrNcCsZtjsttjD]*}|j|krd|vr.|n t|jSqt|tjdddddS)NrenamerF)nametypehelpernoteignore)r_apps_load_definitionsrfindr ApplicationTYPES)Zapp_nameapprrrr$2s  zApplications.findcCstjsttjSN)rr"r#rrrrallDszApplications.allc Cs`tt_tjD]L}zt|WqtyX}z tj|t vrD|WYd}~qd}~00qdSr() r rr" DEFINITIONS_loadrospathdirnamer)fileexrrrr#Ks  zApplications._load_definitionsc Cs"z) __class__rKrQr[rrr__str__szApplication.__str__cCs|Sr()rgr[rrr__repr__szApplication.__repr__cCs|j||dSr()rQrD)rSkeyvaluerrrrDszApplication.setdefaultcCs t|tr|j}|j|dSr()rUr%rQrB)rSvaluesrrrrBs zApplication.updatecCs|jo|jdjS)Nr) instancesis_interpretedr[rrrrmszApplication.is_interpreted)maxsizecCs.|jdr|jdrdS|jo,|jdjS)Nzssh-z-sessionTr)r startswithendswithrl is_sessionr[rrrrqszApplication.is_sessioncCsD|jdtjdkr|jdS|jr.tjdS|jr>tjdStjS)Nrrrr)rQrr&rq is_servicerEr[rrrrs   zApplication.typecCs$tdkr td|jSdS)NrIz {0}.service)r rJr Zunit_path_from_idr7rr[rrrrrs zApplication.is_servicecCsJ|jdpt|}tdkrF|jtjdkrF|rF|dsFd|}|S)Nrrootrzsudo )rQrrFr userrr&ro)rSrrrrrs zApplication.helpercCs|js dSttd|jS)Nz\{.*\}rboolresearchr[rrrhelper_contains_formatingsz%Application.helper_contains_formatingcCs|js dSttd|jS)Nz\{NAME\}rur[rrrhelper_contains_namesz Application.helper_contains_namec CsPg}|jrL|js||jn.|jD]&}||jj|j|j|j|jdq$|S)ab Return the list of helpers which describes how to restart the application. When no ``helper_format`` was described, empty list will be returned. If ``helper_format`` contains process specific arguments such a ``{PID}``, etc. list will contain helper for every application instance. In other cases, there will be just one helper in the list. )NAMEZPNAMEZPIDZEXE)rryrGaffected_instancesr7rpidZexe)rShelpersprocessrrrr~s    zApplication.helperscsjfddS)zo Return collection of processes with same name as application. I.e. running instances of the application csjd||jfvS)Nr)rQr real_name)rr[rrrrz'Application.instances..)processes_factoryr)Zfilteredr[rr[rrls  zApplication.instances)rKrLrM__doc__r rrQrTrXrYr\r`rbrcrgrhrDrBpropertyrmrrqrrrrryrzr~rlr|rrrrr%sF          r%c@s eZdZeddZddZdS)AffectedApplicationcCs|js||_|jSr()rR_namer[rrrr s zAffectedApplication.namecCstdkrt}z|jdj}Wnty8d}Yn0|r|jr||r||ds||d}|rt d|rt dd|S|j r|jdj S|jdS)NrIrZPAMNameIdz \.service$r)r rJr rlr} IndexErrorZunit_path_from_pidZhas_service_property_from_pidZget_unit_property_from_pidrwrxsubrmrrQ)rSZbusr}rrrrr(s      zAffectedApplication._nameN)rKrLrMrrrrrrrrs r)Z __future__rZxml.domrZxml.parsers.expatrZ tracer.pathsrrZtracer.resources.exceptionsrrZtracer.resources.collectionsr Ztracer.resources.langr Ztracer.resources.processesr Ztracer.resources.systemr Ztracer.resources.SystemdDbusr Ztracer.resources.pycomprr,rwobjectrr%rrrrrs         p resources/__pycache__/applications.cpython-39.pyc000064400000023164151114232410016105 0ustar00a "e#@sddlmZddlmZddlmZddlmZmZddl m Z m Z ddl m Z ddlmZddlmZdd lmZdd lmZdd lmZdd lZdd lZGd ddeZGdddZGdddeZd S))absolute_import)minidom) ExpatError)DATA_DIRUSER_CONFIG_DIRS) PathNotFound TracerError)ApplicationsCollection)_) Processes)System) SystemdDbus) lru_cacheNc@seZdZeddegeZddddddd Zed Zd Z e d d Z e ddZ e ddZ eddZeddZe ifddZe ddZd S) ApplicationscCs|dS)Nz/applications.xml)xrrA/usr/lib/python3.9/site-packages/tracer/resources/applications.py%zApplications.daemonZstaticZsession applicationZerasedZ undefined)DAEMONSTATICSESSION APPLICATIONZERASEDUNDEFrNcCsZtjsttjD]*}|j|krd|vr.|n t|jSqt|tjdddddS)NrenamerF)nametypehelpernoteignore)r_apps_load_definitionsrfindr ApplicationTYPES)Zapp_nameapprrrr$2s  zApplications.findcCstjsttjSN)rr"r#rrrrallDszApplications.allc Cs`tt_tjD]L}zt|WqtyX}z tj|t vrD|WYd}~qd}~00qdSr() r rr" DEFINITIONS_loadrospathdirnamer)fileexrrrr#Ks  zApplications._load_definitionsc Cs"z) __class__rKrQr[rrr__str__szApplication.__str__cCs|Sr()rgr[rrr__repr__szApplication.__repr__cCs|j||dSr()rQrD)rSkeyvaluerrrrDszApplication.setdefaultcCs t|tr|j}|j|dSr()rUr%rQrB)rSvaluesrrrrBs zApplication.updatecCs|jo|jdjS)Nr) instancesis_interpretedr[rrrrmszApplication.is_interpreted)maxsizecCs.|jdr|jdrdS|jo,|jdjS)Nzssh-z-sessionTr)r startswithendswithrl is_sessionr[rrrrqszApplication.is_sessioncCsD|jdtjdkr|jdS|jr.tjdS|jr>tjdStjS)Nrrrr)rQrr&rq is_servicerEr[rrrrs   zApplication.typecCs$tdkr td|jSdS)NrIz {0}.service)r rJr Zunit_path_from_idr7rr[rrrrrs zApplication.is_servicecCsJ|jdpt|}tdkrF|jtjdkrF|rF|dsFd|}|S)Nrrootrzsudo )rQrrFr userrr&ro)rSrrrrrs zApplication.helpercCs|js dSttd|jS)Nz\{.*\}rboolresearchr[rrrhelper_contains_formatingsz%Application.helper_contains_formatingcCs|js dSttd|jS)Nz\{NAME\}rur[rrrhelper_contains_namesz Application.helper_contains_namec CsPg}|jrL|js||jn.|jD]&}||jj|j|j|j|jdq$|S)ab Return the list of helpers which describes how to restart the application. When no ``helper_format`` was described, empty list will be returned. If ``helper_format`` contains process specific arguments such a ``{PID}``, etc. list will contain helper for every application instance. In other cases, there will be just one helper in the list. )NAMEZPNAMEZPIDZEXE)rryrGaffected_instancesr7rpidZexe)rShelpersprocessrrrr~s    zApplication.helperscsjfddS)zo Return collection of processes with same name as application. I.e. running instances of the application csjd||jfvS)Nr)rQr real_name)rr[rrrrz'Application.instances..)processes_factoryr)Zfilteredr[rr[rrls  zApplication.instances)rKrLrM__doc__r rrQrTrXrYr\r`rbrcrgrhrDrBpropertyrmrrqrrrrryrzr~rlr|rrrrr%sF          r%c@s eZdZeddZddZdS)AffectedApplicationcCs|js||_|jSr()rR_namer[rrrr s zAffectedApplication.namecCstdkrt}z|jdj}Wnty8d}Yn0|r|jr||r||ds||d}|rt d|rt dd|S|j r|jdj S|jdS)NrIrZPAMNameIdz \.service$r)r rJr rlr} IndexErrorZunit_path_from_pidZhas_service_property_from_pidZget_unit_property_from_pidrwrxsubrmrrQ)rSZbusr}rrrrr(s      zAffectedApplication._nameN)rKrLrMrrrrrrrrs r)Z __future__rZxml.domrZxml.parsers.expatrZ tracer.pathsrrZtracer.resources.exceptionsrrZtracer.resources.collectionsr Ztracer.resources.langr Ztracer.resources.processesr Ztracer.resources.systemr Ztracer.resources.SystemdDbusr Ztracer.resources.pycomprr,rwobjectrr%rrrrrs         p resources/__pycache__/args_parser.cpython-39.opt-1.pyc000064400000004710151114232410016662 0ustar00a "e @sddlZz ddlZWney&Yn0ejdddZejddeddejd d degd d ejd dddddejddddddejddddgdddejddddd dejd!d"d#d$dd%d&ejd'd(d)d*d+d,d-ejd.d/dd0dejd1d2d3dd4dejd5d6d7dd8dejd9d:dd;dejddejd?dgd@dAdBdCeZejdDdEddFdGdHejdIdJdFdKdLdMejdNdOdFdKddMejdPdQddRdSdTze eWne yYn0dS)UNZtracerz9Tracer finds outdated running applications in your system)prog descriptionZpkgs*z Obsolete: Use --packages instead)nargstypehelpz --packagespackagesz#packages that only should be traced)destrrdefaultrz-iz --interactive interactive store_truez]run tracer in interactive mode. Print numbered applications and give helpers based on numbers)r actionrz-nz--nowZnowzXwhen there are specified packages, dont look for time of their update. Use "now" insteadz-tz --timestampZ timestampz since when the updates should be)rr r rz-qz--quietquietz#do not print additional informationz-vz --verboseverbosecountz&print more informations. Use -v or -vv)r r r rz-sz--show+helperZapp_namez!show helper for given application)rr metavarrz --helpersZhelpersz-not list applications, but list their helpersz-az--allallz0list even session and unrestartable applicationsz--daemons-onlyz--services-onlyZ daemons_onlyzlist only daemons/servicesz --hooks-onlyZ hooks_onlyz6do not print traced applications, only run their hooksz --versionversionzprint program versionz--show-resource)rZ processesZrulesZ applicationssystemresourcez,provide informations about selected resource)rchoicesr rz-uz--useruserusername)rr rz-rz--root store_constroot)r r constz-ez --everyonez--erasedZerasedz2print even section with erased packages (DNF only)F)r r rr ) argparseZ argcomplete ImportErrorArgumentParserparser add_argumentstradd_mutually_exclusive_grouprZ autocomplete NameErrorr'r'@/usr/lib/python3.9/site-packages/tracer/resources/args_parser.pys  resources/__pycache__/args_parser.cpython-39.pyc000064400000004710151114232410015723 0ustar00a "e @sddlZz ddlZWney&Yn0ejdddZejddeddejd d degd d ejd dddddejddddddejddddgdddejddddd dejd!d"d#d$dd%d&ejd'd(d)d*d+d,d-ejd.d/dd0dejd1d2d3dd4dejd5d6d7dd8dejd9d:dd;dejddejd?dgd@dAdBdCeZejdDdEddFdGdHejdIdJdFdKdLdMejdNdOdFdKddMejdPdQddRdSdTze eWne yYn0dS)UNZtracerz9Tracer finds outdated running applications in your system)prog descriptionZpkgs*z Obsolete: Use --packages instead)nargstypehelpz --packagespackagesz#packages that only should be traced)destrrdefaultrz-iz --interactive interactive store_truez]run tracer in interactive mode. Print numbered applications and give helpers based on numbers)r actionrz-nz--nowZnowzXwhen there are specified packages, dont look for time of their update. Use "now" insteadz-tz --timestampZ timestampz since when the updates should be)rr r rz-qz--quietquietz#do not print additional informationz-vz --verboseverbosecountz&print more informations. Use -v or -vv)r r r rz-sz--show+helperZapp_namez!show helper for given application)rr metavarrz --helpersZhelpersz-not list applications, but list their helpersz-az--allallz0list even session and unrestartable applicationsz--daemons-onlyz--services-onlyZ daemons_onlyzlist only daemons/servicesz --hooks-onlyZ hooks_onlyz6do not print traced applications, only run their hooksz --versionversionzprint program versionz--show-resource)rZ processesZrulesZ applicationssystemresourcez,provide informations about selected resource)rchoicesr rz-uz--useruserusername)rr rz-rz--root store_constroot)r r constz-ez --everyonez--erasedZerasedz2print even section with erased packages (DNF only)F)r r rr ) argparseZ argcomplete ImportErrorArgumentParserparser add_argumentstradd_mutually_exclusive_grouprZ autocomplete NameErrorr'r'@/usr/lib/python3.9/site-packages/tracer/resources/args_parser.pys  resources/__pycache__/collections.cpython-39.opt-1.pyc000064400000013131151114232410016665 0ustar00a "e1@sxddlmZddlmZddlmZGdddeZGdddeZGdd d eZ Gd d d e Z Gd d d eZ dS))absolute_import) cmp_to_key) NoSuchProcessc@seZdZddZddZdS) CollectioncCs*|D] }t|||kr|||iqdSN)getattrupdate)self attributeZ source_valueZrequired_valueappr @/usr/lib/python3.9/site-packages/tracer/resources/collections.pyreplace_valuesszCollection.replace_valuescs*fdd}fddtt|dS)Ncs@|}|}|sdS|s$dS||kr0dS||kr._sortcs(ttd|rt||St||S)Nr)callabler)r r r r r r6s z!Collection.sorted.._value)key)sortedr)r r rr )rr r r r!s zCollection.sortedN)__name__ __module__ __qualname__rrr r r r rsrc@s<eZdZddZddZddZddZd d Zd d Zd S)ApplicationsCollectioncCstdd|}t|S)NcSs|jSrhelperr r r r Az5ApplicationsCollection.with_helpers..filterrr applicationsr r r with_helpers@sz#ApplicationsCollection.with_helperscCstdd|}t|S)NcSs|j Srrrr r r rErz8ApplicationsCollection.without_helpers..r r"r r r without_helpersDsz&ApplicationsCollection.without_helperscstfdd|}t|S)#app_types -- see Applications.TYPEScs |jvSrtyper app_typesr r rJrz6ApplicationsCollection.exclude_types..r r r*r#r r)r exclude_typesHsz$ApplicationsCollection.exclude_typescstfdd|}t|S)r&cs |jvSrr'rr)r r rOrz5ApplicationsCollection.filter_types..r r+r r)r filter_typesMsz#ApplicationsCollection.filter_typescCs$d}|D]}|j|kr|d7}q|S)Nrrr')r Zapp_typecountZ applicationr r r count_typeRs   z!ApplicationsCollection.count_typecCs tt|Sr)rsetrr r r uniqueYszApplicationsCollection.uniqueN) rrrr$r%r,r-r/r1r r r r r>s rc@s,eZdZddZddZddZddZd S) ProcessesCollectioncss|S|fddS)Ncs |kSr)usernameprocessuserr r rbrz.ProcessesCollection.owned_by..filtered)r r7r r6r owned_by_szProcessesCollection.owned_bycs|fddS)Ncs |kSr)Z create_timer4 timestampr r rerz0ProcessesCollection.newer_than..r8)r r<r r;r newer_thandszProcessesCollection.newer_thanc Cs:t}|D]&}z||Wq ty.Yq 0q t|Sr)r0addrr2)r r1r5r r r r1gs zProcessesCollection.uniquec Cs>t}|D].}z||r"||Wq ty6Yq 0q |Sr)r2appendr)r functionZ processesr5r r r r9nszProcessesCollection.filteredN)rrrr:r=r1r9r r r r r2]sr2c@seZdZddZdS)AffectedProcessesCollectioncCs6|D],}||vr&||||q||qdSr)indexrr?)r iterablexr r r rzsz"AffectedProcessesCollection.updateN)rrrrr r r r rAxsrAc@s4eZdZdZddZddZeddZdd ZdS) PackagesCollectionNcGstj|g|RdSr)list__init__)r argsr r r rGszPackagesCollection.__init__cCs|durtt||S|Sr)rEr0 intersection)r packagesr r r rIszPackagesCollection.intersectioncCs*g}|D]}||j|jqt|Sr)extend_package_managerZ package_filesnamer0)r filespackager r r rNszPackagesCollection.filescCsBi}|D],}|j|vr*||jj|jkr*q|||j<qt|Sr)rMZmodifiedrEvalues)r rJpr r r unique_newests  z PackagesCollection.unique_newest) rrrrLrGrIpropertyrNrRr r r r rEs  rEN) Z __future__r functoolsrZpsutilrrFrrr2rArEr r r r s   % resources/__pycache__/collections.cpython-39.pyc000064400000013131151114232410015726 0ustar00a "e1@sxddlmZddlmZddlmZGdddeZGdddeZGdd d eZ Gd d d e Z Gd d d eZ dS))absolute_import) cmp_to_key) NoSuchProcessc@seZdZddZddZdS) CollectioncCs*|D] }t|||kr|||iqdSN)getattrupdate)self attributeZ source_valueZrequired_valueappr @/usr/lib/python3.9/site-packages/tracer/resources/collections.pyreplace_valuesszCollection.replace_valuescs*fdd}fddtt|dS)Ncs@|}|}|sdS|s$dS||kr0dS||kr._sortcs(ttd|rt||St||S)Nr)callabler)r r r r r r6s z!Collection.sorted.._value)key)sortedr)r r rr )rr r r r!s zCollection.sortedN)__name__ __module__ __qualname__rrr r r r rsrc@s<eZdZddZddZddZddZd d Zd d Zd S)ApplicationsCollectioncCstdd|}t|S)NcSs|jSrhelperr r r r Az5ApplicationsCollection.with_helpers..filterrr applicationsr r r with_helpers@sz#ApplicationsCollection.with_helperscCstdd|}t|S)NcSs|j Srrrr r r rErz8ApplicationsCollection.without_helpers..r r"r r r without_helpersDsz&ApplicationsCollection.without_helperscstfdd|}t|S)#app_types -- see Applications.TYPEScs |jvSrtyper app_typesr r rJrz6ApplicationsCollection.exclude_types..r r r*r#r r)r exclude_typesHsz$ApplicationsCollection.exclude_typescstfdd|}t|S)r&cs |jvSrr'rr)r r rOrz5ApplicationsCollection.filter_types..r r+r r)r filter_typesMsz#ApplicationsCollection.filter_typescCs$d}|D]}|j|kr|d7}q|S)Nrrr')r Zapp_typecountZ applicationr r r count_typeRs   z!ApplicationsCollection.count_typecCs tt|Sr)rsetrr r r uniqueYszApplicationsCollection.uniqueN) rrrr$r%r,r-r/r1r r r r r>s rc@s,eZdZddZddZddZddZd S) ProcessesCollectioncss|S|fddS)Ncs |kSr)usernameprocessuserr r rbrz.ProcessesCollection.owned_by..filtered)r r7r r6r owned_by_szProcessesCollection.owned_bycs|fddS)Ncs |kSr)Z create_timer4 timestampr r rerz0ProcessesCollection.newer_than..r8)r r<r r;r newer_thandszProcessesCollection.newer_thanc Cs:t}|D]&}z||Wq ty.Yq 0q t|Sr)r0addrr2)r r1r5r r r r1gs zProcessesCollection.uniquec Cs>t}|D].}z||r"||Wq ty6Yq 0q |Sr)r2appendr)r functionZ processesr5r r r r9nszProcessesCollection.filteredN)rrrr:r=r1r9r r r r r2]sr2c@seZdZddZdS)AffectedProcessesCollectioncCs6|D],}||vr&||||q||qdSr)indexrr?)r iterablexr r r rzsz"AffectedProcessesCollection.updateN)rrrrr r r r rAxsrAc@s4eZdZdZddZddZeddZdd ZdS) PackagesCollectionNcGstj|g|RdSr)list__init__)r argsr r r rGszPackagesCollection.__init__cCs|durtt||S|Sr)rEr0 intersection)r packagesr r r rIszPackagesCollection.intersectioncCs*g}|D]}||j|jqt|Sr)extend_package_managerZ package_filesnamer0)r filespackager r r rNszPackagesCollection.filescCsBi}|D],}|j|vr*||jj|jkr*q|||j<qt|Sr)rMZmodifiedrEvalues)r rJpr r r unique_newests  z PackagesCollection.unique_newest) rrrrLrGrIpropertyrNrRr r r r rEs  rEN) Z __future__r functoolsrZpsutilrrFrrr2rArEr r r r s   % resources/__pycache__/exceptions.cpython-39.opt-1.pyc000064400000006331151114232410016534 0ustar00a "e @sddlmZddlmZddlmZddlmZddlmZGddde Z Gdd d e e Z Gd d d e e ZGd d d e e ZGddde e ZGddde e ZdS))absolute_import)print_function) version_info) __version___c@seZdZdZddZdS) PrintableNcCs$ttjdkr|jdn|jdS)Nzutf-8)printrmajormessageencodeselfr?/usr/lib/python3.9/site-packages/tracer/resources/exceptions.pyr szPrintable.print)__name__ __module__ __qualname__r r rrrrrsrc@seZdZdZddZdS) TracerErrorz Unspecified tracer error cCs ||_dSN)r )rr rrr__init__%szTracerError.__init__N)rrr__doc__rrrrrr!src@s eZdZeddZddZdS)UnsupportedDistributioncCstdS)NaYou are running unsupported linux distribution Please visit https://github.com/FrostyX/tracer/issues and create new issue called 'Unknown or unsupported linux distribution: {0} (v{1})' if there isn't such. Don't you have an GitHub account? Please report this issue on frostyx@email.czrrrrrr +szUnsupportedDistribution.messagecCst||j|tdSr)OSErrorrr formatr)rZdistrorrrr5sz UnsupportedDistribution.__init__Nrrrpropertyr rrrrrr)s rc@s eZdZeddZddZdS)LockedDatabasecCstdS)Nz-Package database is locked by another processrrrrrr ;szLockedDatabase.messagecCst||jdSrrrr rrrrr?szLockedDatabase.__init__Nrrrrrr9s rc@s eZdZeddZddZdS)DatabasePermissionscCstdS)Nz?You can't open package database due to insufficient permissionsrrrrrr EszDatabasePermissions.messagecCst||jdSrrrrrrrIszDatabasePermissions.__init__Nrrrrrr Cs r c@s eZdZeddZddZdS) PathNotFoundcCstdS)NztProblem occurred - neither one of {0} paths exists Please contact maintainer of tracer package in your distribution.rrrrrr OszPathNotFound.messagecCst||j|dSr)rrr r)rnamerrrrUszPathNotFound.__init__Nrrrrrr!Ms r!N)Z __future__rrsysrZtracer.versionrZtracer.resources.langrobjectr Exceptionrrrrr r!rrrrs       resources/__pycache__/exceptions.cpython-39.pyc000064400000006331151114232410015575 0ustar00a "e @sddlmZddlmZddlmZddlmZddlmZGddde Z Gdd d e e Z Gd d d e e ZGd d d e e ZGddde e ZGddde e ZdS))absolute_import)print_function) version_info) __version___c@seZdZdZddZdS) PrintableNcCs$ttjdkr|jdn|jdS)Nzutf-8)printrmajormessageencodeselfr?/usr/lib/python3.9/site-packages/tracer/resources/exceptions.pyr szPrintable.print)__name__ __module__ __qualname__r r rrrrrsrc@seZdZdZddZdS) TracerErrorz Unspecified tracer error cCs ||_dSN)r )rr rrr__init__%szTracerError.__init__N)rrr__doc__rrrrrr!src@s eZdZeddZddZdS)UnsupportedDistributioncCstdS)NaYou are running unsupported linux distribution Please visit https://github.com/FrostyX/tracer/issues and create new issue called 'Unknown or unsupported linux distribution: {0} (v{1})' if there isn't such. Don't you have an GitHub account? Please report this issue on frostyx@email.czrrrrrr +szUnsupportedDistribution.messagecCst||j|tdSr)OSErrorrr formatr)rZdistrorrrr5sz UnsupportedDistribution.__init__Nrrrpropertyr rrrrrr)s rc@s eZdZeddZddZdS)LockedDatabasecCstdS)Nz-Package database is locked by another processrrrrrr ;szLockedDatabase.messagecCst||jdSrrrr rrrrr?szLockedDatabase.__init__Nrrrrrr9s rc@s eZdZeddZddZdS)DatabasePermissionscCstdS)Nz?You can't open package database due to insufficient permissionsrrrrrr EszDatabasePermissions.messagecCst||jdSrrrrrrrIszDatabasePermissions.__init__Nrrrrrr Cs r c@s eZdZeddZddZdS) PathNotFoundcCstdS)NztProblem occurred - neither one of {0} paths exists Please contact maintainer of tracer package in your distribution.rrrrrr OszPathNotFound.messagecCst||j|dSr)rrr r)rnamerrrrUszPathNotFound.__init__Nrrrrrr!Ms r!N)Z __future__rrsysrZtracer.versionrZtracer.resources.langrobjectr Exceptionrrrrr r!rrrrs       resources/__pycache__/lang.cpython-39.opt-1.pyc000064400000000777151114232410015304 0ustar00a "e@stddlmZddlZddlZddlmZddlmZddlmZej dkrZeje_ ej e_ ej dded Zej ZdS) )absolute_importN)NullTranslations) version_info)LANG_DIRZtracerT)fallback localedir)Z __future__rlocalegettextrsysrZ tracer.pathsrmajorZugettextngettextZ ungettext translationt_rr9/usr/lib/python3.9/site-packages/tracer/resources/lang.pys     resources/__pycache__/lang.cpython-39.pyc000064400000000777151114232410014345 0ustar00a "e@stddlmZddlZddlZddlmZddlmZddlmZej dkrZeje_ ej e_ ej dded Zej ZdS) )absolute_importN)NullTranslations) version_info)LANG_DIRZtracerT)fallback localedir)Z __future__rlocalegettextrsysrZ tracer.pathsrmajorZugettextngettextZ ungettext translationt_rr9/usr/lib/python3.9/site-packages/tracer/resources/lang.pys     resources/__pycache__/memory.cpython-39.opt-1.pyc000064400000001417151114232410015663 0ustar00a "ez@s.ddlmZddlmZddlZdddZdS))absolute_import) ProcessesNc Cszi}t|D]^}z2|jD]&}||vr>|||q"|g||<q"Wqtjy`YqtjyrYq0q|S)z Returns memory in BTree structure { file_1 : [process_1, process_2, ..., process_n], ... } Which describes that processes 1 to `n` is using file_1 ) rallZowned_byuniquefilesappendpsutilZ NoSuchProcessZ AccessDenied)userZmemoryZprocessfiler ;/usr/lib/python3.9/site-packages/tracer/resources/memory.py dump_memorys  r )N)Z __future__rZtracer.resources.processesrrr r r r r s  resources/__pycache__/memory.cpython-39.pyc000064400000001417151114232410014724 0ustar00a "ez@s.ddlmZddlmZddlZdddZdS))absolute_import) ProcessesNc Cszi}t|D]^}z2|jD]&}||vr>|||q"|g||<q"Wqtjy`YqtjyrYq0q|S)z Returns memory in BTree structure { file_1 : [process_1, process_2, ..., process_n], ... } Which describes that processes 1 to `n` is using file_1 ) rallZowned_byuniquefilesappendpsutilZ NoSuchProcessZ AccessDenied)userZmemoryZprocessfiler ;/usr/lib/python3.9/site-packages/tracer/resources/memory.py dump_memorys  r )N)Z __future__rZtracer.resources.processesrrr r r r r s  resources/__pycache__/package.cpython-39.opt-1.pyc000064400000003022151114232410015740 0ustar00a "eJ@sddlmZGdddZdS))absolute_importc@sfeZdZdZdZdZdZdZdZdZ dZ dddZ ddZ ddZ d d Zd d Zd dZddZdS)PackagezRepresents linux packageNcCs||_||_dSN)namemodified)selfrrrrrrrr __repr__-szPackage.__repr__cCs|jSrrrrrr __str__0szPackage.__str__cCs t|jSr)hashrrrrr __hash__3szPackage.__hash__cCs||dSr)Zload_package_info)rZpackage_managerrrr load_info6szPackage.load_info)N)__name__ __module__ __qualname____doc__rr descriptioncategoryZepochversionreleaser rrrrrrrrrr rs rN)Z __future__rrrrrr s resources/FilenameCleaner.py000064400000006273151114232410012144 0ustar00#-*- coding: utf-8 -*- # FilenameCleaner.py # Module to stripping the version numers from filenames # # i.e.: # /lib/libdl-2.19.so --> /lib/libdl.so # /lib/libncurses.so.5.9 --> /lib/libncurses.so # # This implementation really sux and surely there is a much better # way how to implement following methods. They are properly tested # in `test_FilenameCleaner.py` so feel free to refactor them. # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # class FilenameCleaner(object): @staticmethod def strip(filename): filename = FilenameCleaner._strip_abnormalities(filename) try: slash = filename.rindex('/') dirname = filename[:slash] basename = filename[slash+1:] if "." in basename: basename = FilenameCleaner._strip_around_so_delimited_dots(basename) basename = FilenameCleaner._strip_after_dash(basename) return dirname + '/' + basename except IndexError: pass except ValueError: pass return filename @staticmethod def _strip_abnormalities(filename): # Doesnt matter what is after space cause filename ends with first space try: filename = filename[:filename.index(' ')] except ValueError: pass # On Gentoo, there is #new after some files in lsof # i.e. /usr/bin/gvim#new (deleted) if filename.endswith('#new'): filename = filename[0:-4] # On Fedora, there is something like ;541350b3 after some files in lsof # See issue #9 if ';' in filename: filename = filename[0:filename.index(';')] # On Fedora, there is something like .#prelink#.N3n7Rk (deleted) after some files in lsof # See issue #9 if '.#prelink#.' in filename: filename = filename[0:filename.rindex('.#prelink#.')] return filename @staticmethod def _strip_around_so_delimited_dots(basename): try: split = basename.split(".so") basename = split[0] if len(split) > 1: basename += ".so" first_dot_i = basename.index(".") last_dot_i = basename.rindex(".") basename = basename[:first_dot_i] + basename[last_dot_i:] except IndexError: pass except ValueError: pass return basename @staticmethod def _strip_after_dash(basename): try: dash = basename.rindex("-") dot = basename.index(".", dash) if FilenameCleaner._is_version(basename[dash+1:dot]): basename = basename[:dash] + basename[dot:] except IndexError: pass except ValueError: pass return basename @staticmethod def _is_version(string): """ Returns True if string contains only digits and dots """ for char in string: if (not char.isdigit()) or char == ".": return False return True resources/PackageManager.py000064400000005330151114232410011751 0ustar00#-*- coding: utf-8 -*- # PackageManager.py # Wrapper class for package managers. # Provides their API and allows to use multiple package managers at once. # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import import itertools class PackageManager: """ Wrapper class for package managers. Provides their API and allows to use multiple package managers at once. In actions where it makes no sense to merge results from more package managers, result from first manager is used. """ package_managers = None def __init__(self, *instances): self.package_managers = instances def names(self): return map(lambda x: x.__class__.__name__ ,self.package_managers) def packages_newer_than(self, unix_time): """ Returns list of packages which were modified between unix_time and present Packages in list should be dictionaries with keys {"name", "modified"} """ # @FIXME move import to top-level from tracer.resources.collections import PackagesCollection packages_lists = [p.packages_newer_than(unix_time) for p in self.package_managers] return PackagesCollection(itertools.chain.from_iterable(packages_lists)) def package_files(self, pkg_name): """Returns list of files provided by package""" return self.package_managers[0].package_files(pkg_name) def load_package_info(self, package): """From database load informations about given package and set them to it""" return self.package_managers[0].load_package_info(package) def provided_by(self, app): """Returns name of package which provides given application""" return self.package_managers[0].provided_by(app) def find_package(self, pkg_name, search): """Find a package by name and some other input criteria""" return self.package_managers[0].find_package(pkg_name, search) def compare_packages(self, package1, package2): """ Compares two packages by their version information Returns: 0 if they are equal 1 if package1 > package2 -1 if package2 > package1 """ return self.package_managers[0].compare_packages(package1, package2) resources/SystemdDbus.py000064400000004056151114232410011375 0ustar00# SystemdUnit.py # Module for getting data from Systemd about Units # Copyright (C) 2017 Sean O'Keeffe # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # import dbus class SystemdDbus(object): def __init__(self): self.__systemd = dbus.SystemBus().get_object('org.freedesktop.systemd1','/org/freedesktop/systemd1') self.__manager = dbus.Interface(self.__systemd, dbus_interface='org.freedesktop.systemd1.Manager') def unit_path_from_pid(self, pid): try: return self.__manager.GetUnitByPID(pid) except dbus.exceptions.DBusException: return False def unit_path_from_id(self, Id): try: return self.__manager.GetUnit(Id) except dbus.exceptions.DBusException: return False def has_service_property_from_pid(self, pid, attr): try: unit = self.unit_path_from_pid(pid) if not unit: return False proxy = dbus.SystemBus().get_object('org.freedesktop.systemd1', unit) propty = proxy.Get('org.freedesktop.systemd1.Service', attr, dbus_interface='org.freedesktop.DBus.Properties') except dbus.exceptions.DBusException: return False return bool(propty) def get_unit_property_from_pid(self, pid, attr): unit_path = self.unit_path_from_pid(pid) if bool(unit_path): proxy = dbus.SystemBus().get_object('org.freedesktop.systemd1', self.unit_path_from_pid(pid)) return proxy.Get('org.freedesktop.systemd1.Unit', attr, dbus_interface='org.freedesktop.DBus.Properties') else: return False resources/__init__.py000064400000000000151114232410010647 0ustar00resources/applications.py000064400000021712151114232410011613 0ustar00#-*- coding: utf-8 -*- # applications.py # Manager for applications file # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from xml.dom import minidom from xml.parsers.expat import ExpatError from tracer.paths import DATA_DIR, USER_CONFIG_DIRS from tracer.resources.exceptions import PathNotFound, TracerError from tracer.resources.collections import ApplicationsCollection from tracer.resources.lang import _ from tracer.resources.processes import Processes from tracer.resources.system import System from tracer.resources.SystemdDbus import SystemdDbus from tracer.resources.pycomp import lru_cache import os import re class Applications(object): DEFINITIONS = map(lambda x: x + "/applications.xml", [DATA_DIR] + USER_CONFIG_DIRS) TYPES = { "DAEMON" : "daemon", "STATIC" : "static", "SESSION" : "session", "APPLICATION" : "application", "ERASED" : "erased", "UNDEF" : "undefined" #Internal only } DEFAULT_TYPE = TYPES["APPLICATION"] _apps = None @staticmethod def find(app_name): if not Applications._apps: Applications._load_definitions() for app in Applications._apps: if app.name == app_name: return app if "rename" not in app else Applications.find(app.rename) # Return the default application return Application({ "name": app_name, "type": Applications.TYPES["UNDEF"], "helper": None, "note": None, "ignore": False, }) @staticmethod def all(): if not Applications._apps: Applications._load_definitions() return Applications._apps @staticmethod def _load_definitions(): Applications._apps = ApplicationsCollection() for file in Applications.DEFINITIONS: try: Applications._load(file) except PathNotFound as ex: if not os.path.dirname(file) in USER_CONFIG_DIRS: raise ex @classmethod def _load(cls, file): try: with open(file, "r") as f: xmldoc = minidom.parseString(f.read()) except IOError: raise PathNotFound('DATA_DIR') except ExpatError as ex: msg = "Unable to parse {0}\nHint: {1}".format(file, ex) raise TracerError(msg) for applications in xmldoc.getElementsByTagName("applications"): cls._remove_unwanted_children(applications) for child in applications.childNodes: if child.nodeName == "app": attrs = dict(child.attributes.items()) Applications._append_application(attrs) if child.nodeName == "group": cls._remove_unwanted_children(child) for app in child.childNodes: app_attrs = dict(app.attributes.items()) group_attrs = dict(child.attributes.items()) Applications._append_application(app_attrs, group_attrs) @classmethod def _remove_unwanted_children(cls, node): for child in node.childNodes: if child.nodeType != node.ELEMENT_NODE: node.removeChild(child) @staticmethod def _append_application(default_attrs, specific_attrs={}): application = Application(default_attrs) application.update(specific_attrs) if application in Applications._apps: i = Applications._apps.index(application) Applications._apps[i].update(application) else: application.setdefault('type', Applications.DEFAULT_TYPE) application.setdefault('helper', Applications._helper(application)) application.setdefault('note', None) application.setdefault('ignore', False) Applications._apps.append(application) @staticmethod def _helper(app): if app.type == Applications.TYPES["DAEMON"]: if System.init_system() == "systemd": return "systemctl restart {0}".format(app.name) else: return "service {0} restart".format(app.name) elif app.type == Applications.TYPES["STATIC"]: return _("You will have to reboot your computer") elif app.type == Applications.TYPES["SESSION"]: return _("You will have to log out & log in again") return None class Application: """ Represent the application defined in ``applications.xml`` :param str name: The name of the application :param str type: See ``Applications.TYPES`` for possible values :param str helper: Describes how to restart the applications :param bool note: Provides additional informations to the ``helper`` :param bool ignore: If ``True``, the application won't be printed :param Processes processes_factory: Class providing list of running processes """ processes_factory = Processes _attributes = None def __init__(self, attributes_dict): self._attributes = attributes_dict self._cached_name = None def __eq__(self, other): return isinstance(other, Application) and self.name == other.name def __ne__(self, other): return not self.__eq__(other) def __hash__(self): return hash(self.name) def __getattr__(self, item): return self._attributes[item] def __len__(self): return len(self._attributes) def __contains__(self, item): return item in self._attributes def __str__(self): return "<" + self.__class__.__name__ + ": " + self._attributes["name"] + ">" def __repr__(self): return self.__str__() def setdefault(self, key, value): self._attributes.setdefault(key, value) def update(self, values): if isinstance(values, Application): values = values._attributes self._attributes.update(values) @property def is_interpreted(self): # @TODO check all instances return self.instances and self.instances[0].is_interpreted @property @lru_cache(maxsize=None) def is_session(self): if self.name.startswith("ssh-") and self.name.endswith("-session"): return True return self.instances and self.instances[0].is_session @property def type(self): if self._attributes["type"] != Applications.TYPES["UNDEF"]: return self._attributes["type"] if self.is_session: return Applications.TYPES["SESSION"] if self.is_service: return Applications.TYPES["DAEMON"] return Applications.DEFAULT_TYPE @property @lru_cache(maxsize=None) def is_service(self): if System.init_system() == "systemd": return SystemdDbus().unit_path_from_id("{0}.service".format(self.name)) # @TODO rename to helper_format @property def helper(self): helper = self._attributes["helper"] or Applications._helper(self) if System.user() != "root" and self.type == Applications.TYPES["DAEMON"]: if helper and not helper.startswith("sudo "): helper = "sudo " + helper return helper @property def helper_contains_formating(self): if not self.helper: return None return bool(re.search(r"\{.*\}", self.helper)) @property def helper_contains_name(self): if not self.helper: return None return bool(re.search(r"\{NAME\}", self.helper)) @property def helpers(self): """ Return the list of helpers which describes how to restart the application. When no ``helper_format`` was described, empty list will be returned. If ``helper_format`` contains process specific arguments such a ``{PID}``, etc. list will contain helper for every application instance. In other cases, there will be just one helper in the list. """ helpers = [] if self.helper: if not self.helper_contains_formating: helpers.append(self.helper) else: for process in self.affected_instances: helpers.append(self.helper.format( NAME=self.name, PNAME=process.name, PID=process.pid, EXE=process.exe, )) return helpers @property def instances(self): """ Return collection of processes with same name as application. I.e. running instances of the application """ return self.processes_factory.all().filtered( lambda process: self._attributes["name"] in [process.name(), process.real_name]) affected_instances = None class AffectedApplication(Application): @property def name(self): # We need to cache manually instead of using `@lru_cache` because this # property is used for self.__hash__ if not self._cached_name: self._cached_name = self._name() return self._cached_name def _name(self): if System.init_system() == "systemd": bus = SystemdDbus() # Trying to access `self.instances` just once try: pid = self.instances[0].pid except IndexError: pid = None if pid: if self.instances and bus.unit_path_from_pid(pid): if not bus.has_service_property_from_pid(pid, 'PAMName'): Id = bus.get_unit_property_from_pid(pid, 'Id') if Id and re.search(r"\.service$", Id): return re.sub(r'\.service$', '', Id) if self.is_interpreted: return self.instances[0].real_name return self._attributes["name"] resources/args_parser.py000064400000006653151114232410011444 0ustar00#-*- coding: utf-8 -*- # args_parser.py # Module for parsing console arguments # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # import argparse try: import argcomplete except ImportError: pass parser = argparse.ArgumentParser( prog = 'tracer', description='Tracer finds outdated running applications in your system', ) # Obsolete parser.add_argument('pkgs', nargs='*', type=str, help='Obsolete: Use --packages instead' ) parser.add_argument('--packages', dest='packages', nargs='*', type=str, default=[], help='packages that only should be traced' ) parser.add_argument('-i', '--interactive', dest='interactive', action='store_true', help='run tracer in interactive mode. Print numbered applications and give helpers based on numbers' ) parser.add_argument('-n', '--now', dest='now', action='store_true', help='when there are specified packages, dont look for time of their update. Use "now" instead' ) parser.add_argument('-t', '--timestamp', nargs=1, default=[None], dest='timestamp', help='since when the updates should be' ) parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help='do not print additional information' ) parser.add_argument('-v', '--verbose', dest='verbose', action='count', default=0, help='print more informations. Use -v or -vv' ) parser.add_argument('-s', '--show', nargs='+', dest='helper', metavar='app_name', help='show helper for given application' ) parser.add_argument('--helpers', dest='helpers', action='store_true', help='not list applications, but list their helpers' ) parser.add_argument('-a', '--all', dest='all', action='store_true', help='list even session and unrestartable applications' ) parser.add_argument('--daemons-only', '--services-only', dest='daemons_only', action='store_true', help='list only daemons/services' ) parser.add_argument('--hooks-only', dest='hooks_only', action='store_true', help='do not print traced applications, only run their hooks' ) parser.add_argument('--version', dest='version', action='store_true', help='print program version' ) parser.add_argument('--show-resource', nargs=1, choices=['packages', 'processes', 'rules', 'applications', 'system'], dest='resource', help='provide informations about selected resource' ) user = parser.add_mutually_exclusive_group() user.add_argument("-u", "--user", nargs=1, dest='user', metavar='username' ) user.add_argument("-r", "--root", dest='user', action="store_const", const='root' ) user.add_argument("-e", "--everyone", dest='user', action="store_const", const='*' ) user.add_argument("--erased", dest="erased", action="store_true", help="print even section with erased packages (DNF only)", default=False ) try: argcomplete.autocomplete(parser) except NameError: pass resources/collections.py000064400000010061151114232410011436 0ustar00#-*- coding: utf-8 -*- # collections.py # Define various kind of collections # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from functools import cmp_to_key from psutil import NoSuchProcess class Collection(list): def replace_values(self, attribute, source_value, required_value): for app in self: if getattr(app, attribute) == source_value: app.update({attribute: required_value}) def sorted(self, attribute): def _sort(app1, app2): value1 = _value(app1, attribute) value2 = _value(app2, attribute) # Make sure the None values are at the end # This shouldn't happen anyway but sometimes if does, # for some reason, see #151 or #156 if not value1: return 1 if not value2: return -1 # https://stackoverflow.com/a/13239857/3285282 if value1 < value2: return -1 if value1 > value2: return 1 return 0 def _value(app, attribute): if callable(getattr(self[0], attribute)): return getattr(app, attribute)() return getattr(app, attribute) return sorted(self, key=cmp_to_key(_sort)) class ApplicationsCollection(Collection): def with_helpers(self): applications = filter(lambda app: app.helper, self) return ApplicationsCollection(applications) def without_helpers(self): applications = filter(lambda app: not app.helper, self) return ApplicationsCollection(applications) def exclude_types(self, app_types): """app_types -- see Applications.TYPES""" applications = filter(lambda app: app.type not in app_types, self) return ApplicationsCollection(applications) def filter_types(self, app_types): """app_types -- see Applications.TYPES""" applications = filter(lambda app: app.type in app_types, self) return ApplicationsCollection(applications) def count_type(self, app_type): count = 0 for application in self: if application.type == app_type: count += 1 return count def unique(self): return ApplicationsCollection(set(self)) class ProcessesCollection(Collection): def owned_by(self, user): if not user: return self return self.filtered(lambda process: process.username() == user) def newer_than(self, timestamp): return self.filtered(lambda process: process.create_time() >= timestamp) def unique(self): unique = set() for process in self: try: unique.add(process) except NoSuchProcess: pass return ProcessesCollection(unique) def filtered(self, function): processes = ProcessesCollection() for process in self: try: if function(process): processes.append(process) except NoSuchProcess: pass return processes class AffectedProcessesCollection(ProcessesCollection): def update(self, iterable): for x in iterable: if x in self: self[self.index(x)].update(x) else: self.append(x) class PackagesCollection(Collection): _package_manager = None def __init__(self, *args): list.__init__(self, *args) def intersection(self, packages): if packages is not None: return PackagesCollection(set(packages).intersection(self)) return self @property def files(self): files = [] for package in self: files.extend(self._package_manager.package_files(package.name)) return set(files) def unique_newest(self): packages = {} for p in self: if p.name in packages: if packages[p.name].modified > p.modified: continue packages[p.name] = p return PackagesCollection(packages.values()) resources/exceptions.py000064400000004704151114232410011310 0ustar00#-*- coding: utf-8 -*- # exceptions.py # Tracer exceptions module # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from __future__ import print_function from sys import version_info from tracer.version import __version__ from tracer.resources.lang import _ class Printable(object): message = None def print(self): print(self.message.encode("utf-8") if version_info.major == 2 else self.message) class TracerError(Exception, Printable): """ Unspecified tracer error """ def __init__(self, message): self.message = message class UnsupportedDistribution(OSError, Printable): @property def message(self): return _( "You are running unsupported linux distribution\n" "\n" "Please visit https://github.com/FrostyX/tracer/issues\n" "and create new issue called 'Unknown or unsupported linux distribution: {0} (v{1})' if there isn't such.\n" "\n" "Don't you have an GitHub account? Please report this issue on frostyx@email.cz") def __init__(self, distro): OSError.__init__(self, self.message.format(distro, __version__)) class LockedDatabase(OSError, Printable): @property def message(self): return _("Package database is locked by another process") def __init__(self): OSError.__init__(self, self.message) class DatabasePermissions(OSError, Printable): @property def message(self): return _("You can't open package database due to insufficient permissions") def __init__(self): OSError.__init__(self, self.message) class PathNotFound(OSError, Printable): @property def message(self): return _( "Problem occurred - neither one of {0} paths exists\n" "Please contact maintainer of tracer package in your distribution.") def __init__(self, name): OSError.__init__(self, self.message.format(name)) resources/lang.py000064400000002421151114232410010042 0ustar00#-*- coding: utf-8 -*- # lang.py # Module working with language localizations # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import import locale import gettext from gettext import NullTranslations from sys import version_info from tracer.paths import LANG_DIR # python 3 compabillity settings if version_info.major >= 3: # u?gettext dont exists in python3 NullTranslations NullTranslations.ugettext = NullTranslations.gettext NullTranslations.ungettext = NullTranslations.ngettext t = gettext.translation('tracer', fallback=True, localedir=LANG_DIR) _ = t.ugettext resources/memory.py000064400000002572151114232410010440 0ustar00#-*- coding: utf-8 -*- # memory.py # Module to work with files in memory # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from tracer.resources.processes import Processes import psutil def dump_memory(user=None): """ Returns memory in BTree structure { file_1 : [process_1, process_2, ..., process_n], ... } Which describes that processes 1 to `n` is using file_1 """ memory = {} for process in Processes.all().owned_by(user).unique(): try: for file in process.files: if file in memory: memory[file].append(process) else: memory[file] = [process] except psutil.NoSuchProcess: pass except psutil.AccessDenied: pass return memory resources/package.py000064400000003112151114232410010512 0ustar00#-*- coding: utf-8 -*- # package.py # Represents linux package # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import class Package: """Represents linux package""" name = None #: Name of the package modified = None #: UNIX timestamp of the modification description = None category = None epoch = None version = None release = None def __init__(self, name, modified=None): self.name = name self.modified = modified def __eq__(self, package): """Packages are equal when they have same name""" return (isinstance(package, self.__class__) and self.name == package.name) def __ne__(self, package): return not self.__eq__(package) def __repr__(self): return "" def __str__(self): return self.name def __hash__(self): return hash(self.name) def load_info(self, package_manager): package_manager.load_package_info(self) resources/processes.py000064400000021561151114232410011135 0ustar00#-*- coding: utf-8 -*- # processes.py # Module providing informations about processes # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from .collections import ProcessesCollection from .FilenameCleaner import FilenameCleaner import psutil import datetime import time import os from subprocess import PIPE, Popen from threading import Timer from six import with_metaclass class Processes(object): # psutil 3.x to 1.x backward compatibility @staticmethod def pids(): try: return psutil.pids() except AttributeError: return psutil.get_pid_list() @staticmethod def all(): processes = ProcessesCollection() for pid in Processes.pids(): try: processes.append(Process(pid)) except psutil.NoSuchProcess: pass except psutil.AccessDenied: pass return processes class ProcessWrapper(object): """ Wrapper for ``psutil.Process class`` Library ``psutil`` is not backward compatible from version 2.x.x to 1.x.x. Purpose of this class is cover incompatibility in ``psutil.Process`` class and provide interface of new version. It allows using new interface even with old version of ``psutil``. Note that, for performance reasons, process information is cached at object creation. To force a refresh, invoke the ``rebuild_cache()`` method. """ def __init__(self, pid=None): self._process = psutil.Process(pid) self.rebuild_cache() def __nonzero__(self): return bool(self._process) def rebuild_cache(self): self._procdict = self._process.as_dict(attrs=['name', 'exe', 'cmdline', 'ppid', 'username', 'create_time']) def name(self): # Special case for sshd, if its cmd contains the execuatable is must be the daemon # else must be the session. try: if self._attr("name") == 'sshd': if self._attr("exe") not in self._attr("cmdline") and len(self._attr("cmdline")) > 1: username= self._attr("cmdline")[1].split("@")[0] return 'ssh-{0}-session'.format(username) except psutil.AccessDenied: pass return self._attr("name") def exe(self): return self._attr("exe") def cmdline(self): return self._attr("cmdline") def ppid(self): return self._attr("ppid") def parent(self): return self._attr("parent") def username(self): return self._attr("username") def create_time(self): return self._attr("create_time") def children(self, recursive=False): key = 'children-{0}'.format(recursive) if key not in self._procdict: try: self._procdict[key] = self._process.children(recursive) except AttributeError: self._procdict[key] = self._process.get_children(recursive) return self._procdict[key] def _attr(self, name): if name not in self._procdict: attr = getattr(self._process, name) try: self._procdict[name] = attr() except TypeError: self._procdict[name] = attr return self._procdict[name] def __getattr__(self, item): return getattr(self._process, item) # psutil 3.x to 1.x backward compatibility def memory_maps(self, grouped=True): key = 'memory_maps-{0}'.format(grouped) if key not in self._procdict: try: self._procdict[key] = self._process.memory_maps(grouped=grouped) except AttributeError: self._procdict[key] = self._process.get_memory_maps(grouped=grouped) return self._procdict[key] class ProcessMeta(type): """ Caching metaclass that ensures that only one ``Process`` object is ever instantiated for any given PID. The cache can be cleared by calling ``Process.reset_cache()``. Based on https://stackoverflow.com/a/33458129 """ def __init__(cls, name, bases, attributes): super(ProcessMeta, cls).__init__(name, bases, attributes) def reset_cache(): cls._cache = {} reset_cache() setattr(cls, 'reset_cache', reset_cache) def __call__(cls, *args, **kwargs): pid = args[0] if pid not in cls._cache: self = cls.__new__(cls, *args, **kwargs) cls.__init__(self, *args, **kwargs) cls._cache[pid] = self return cls._cache[pid] class Process(with_metaclass(ProcessMeta, ProcessWrapper)): """ Represent the process instance uniquely identifiable through PID For all class properties and methods, please see http://pythonhosted.org/psutil/#process-class Below listed are only reimplemented ones. For performance reasons, instances are cached based on PID, and multiple instantiations of a ``Process`` object with the same PID will return the same object. To clear the cache, invoke ``Process.reset_cache()``. Additionally, as with ``ProcessWrapper``, process information is cached at object creation. To force a refresh, invoke the ``rebuild_cache()`` method on the object. """ def __eq__(self, process): """For our purposes, two processes are equal when they have same name""" return self.pid == process.pid def __ne__(self, process): return not self.__eq__(process) def __hash__(self): return hash(self.pid) @staticmethod def safe_isfile(file_path, timeout=0.5): """ Process arguments could be referring to files on remote filesystems and os.path.isfile will hang forever if the shared FS is offline. Instead, use a subprocess that we can time out if we can't reach some file. """ process = Popen(['test', '-f', file_path], stdout=PIPE, stderr=PIPE) timer = Timer(timeout, process.kill) try: timer.start() process.communicate() return process.returncode == 0 finally: timer.cancel() @property def files(self): files = [] # Files from memory maps for mmap in self.memory_maps(): files.append(FilenameCleaner.strip(mmap.path)) # Process arguments for arg in self.cmdline()[1:]: if not os.path.isabs(arg): continue if Process.safe_isfile(arg): files.append(arg) return sorted(files) def parent(self): """The parent process casted from ``psutil.Process`` to tracer ``Process``""" if self.ppid(): return Process(self.ppid()) return None def username(self): """The user who owns the process. If user was deleted in the meantime, ``None`` is returned instead.""" # User who run the process can be deleted try: return super(Process, self).username() except KeyError: return None def children(self, recursive=False): """The collection of process's children. Each of them casted from ``psutil.Process`` to tracer ``Process``.""" children = super(Process, self).children(recursive) return ProcessesCollection([Process(child.pid) for child in children]) @property def exe(self): """The absolute path to process executable. Cleaned from arbitrary strings which appears on the end.""" # On Gentoo, there is #new after some files in lsof # i.e. /usr/bin/gvim#new (deleted) exe = super(Process, self).exe() if exe.endswith('#new'): exe = exe[0:-4] # On Fedora, there is something like ;541350b3 after some files in lsof if ';' in exe: exe = exe[0:exe.index(';')] return exe @property def is_interpreted(self): # @TODO implement better detection of interpreted processes return self.name() in ["python"] @property def is_session(self): terminal = self.terminal() if terminal is None: return None parent = self.parent() if parent is None or terminal != parent.terminal(): return True @property def real_name(self): if self.is_interpreted: for arg in self.cmdline()[1:]: if os.path.isfile(arg): return os.path.basename(arg) return self.name() @property def str_started_ago(self): """ The time of how long process is running. Returned as string in format ``XX unit`` where unit is one of ``days`` | ``hours`` | ``minutes`` | ``seconds`` """ now = datetime.datetime.fromtimestamp(time.time()) started = datetime.datetime.fromtimestamp(self.create_time()) started = now - started started_str = "" if started.days > 0: started_str = str(started.days) + " days" elif started.seconds >= 60 * 60: started_str = str(int(started.seconds / (60 * 60))) + " hours" elif started.seconds >= 60: started_str = str(int(started.seconds / 60)) + " minutes" elif started.seconds >= 0: started_str = str(int(started.seconds)) + " seconds" return started_str class AffectedProcess(Process): packages = None files = None def __init__(self, pid=None): Process.__init__(self, pid) self.packages = set() self.files = set() def update(self, process): self.files = self.files.union(process.files) self.packages = self.packages.union(process.packages) resources/pycomp.py000064400000002751151114232410010436 0ustar00#-*- coding: utf-8 -*- # pycomp.py # Compatibility layer between python2 and python3 # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from sys import version_info PY3 = version_info.major >= 3 if PY3: from io import StringIO from functools import lru_cache else: from StringIO import StringIO from backports.functools_lru_cache import lru_cache def load_source(module_name, path): """ Read and evaluate a python file This is useful when we don't know the module name beforehand and somehow figure it out at the runtime (e.g. user-defined hook files) """ if not PY3: import imp return imp.load_source(module_name, path) from importlib.machinery import SourceFileLoader import types loader = SourceFileLoader(module_name, path) loaded = types.ModuleType(loader.name) return loader.exec_module(loaded) resources/router.py000064400000003445151114232410010450 0ustar00#-*- coding: utf-8 -*- # router.py # Router chooses the right controller and its method and calls it # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import import os from tracer.version import __version__ from tracer.resources.lang import _ # WARNING: There are local imports in dispatch method class Router: args = None packages = None def __init__(self, args, packages): self.args = args self.packages = packages def dispatch(self): if self.args.helper: from tracer.controllers.helper import HelperController controller = HelperController(self.args, self.packages) controller.render() elif self.args.version: print(__version__) elif self.args.resource: from tracer.controllers.resource import ResourceController controller = ResourceController(self.args) controller.render() else: from tracer.controllers.default import DefaultController controller = DefaultController(self.args, self.packages) if self.args.helpers: controller.render_helpers() elif self.args.interactive: controller.render_interactive() else: controller.render() resources/rules.py000064400000006356151114232410010266 0ustar00#-*- coding: utf-8 -*- # rules.py # Manager for rules file # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import from xml.dom import minidom from xml.parsers.expat import ExpatError from tracer.paths import DATA_DIR, USER_CONFIG_DIRS from tracer.resources.exceptions import PathNotFound, TracerError from os.path import dirname class Rules(object): DEFINITIONS = map(lambda x: x + "/rules.xml", [DATA_DIR] + USER_CONFIG_DIRS) ACTIONS = { "CALL-PARENT" : "call-parent", "RETURN" : "return", } _DEFAULT_ACTION = ACTIONS["CALL-PARENT"] _rules = None @staticmethod def find(app_name): if not Rules._rules: Rules._load_definitions() for rule in Rules._rules: if rule.name == app_name: return rule @staticmethod def all(): if not Rules._rules: Rules._load_definitions() return Rules._rules @staticmethod def _load_definitions(): Rules._rules = [] for file in Rules.DEFINITIONS: try: Rules._load(file); except PathNotFound as ex: if not dirname(file) in USER_CONFIG_DIRS: raise ex @staticmethod def _load(file): try: with open(file, "r") as f: xmldoc = minidom.parseString(f.read()) except IOError: raise PathNotFound('DATA_DIR') except ExpatError as ex: msg = "Unable to parse {0}\nHint: {1}".format(file, ex) raise TracerError(msg) for rules in xmldoc.getElementsByTagName("rules"): for rule in rules.getElementsByTagName("rule"): attrs = dict(rule.attributes.items()) r = Rule(attrs) if r in Rules._rules: i = Rules._rules.index(r) Rules._rules[i].update(r) else: r.setdefault('action', Rules._DEFAULT_ACTION) Rules._rules.append(r) class Rule(object): """ Represent the rule defined in `rules.xml` Attributes ---------- name : str action : str See `Rules.ACTIONS` for possible values """ _attributes = None def __init__(self, attributes_dict): self._attributes = attributes_dict def __eq__(self, other): return isinstance(other, Rule) and self.name == other.name def __ne__(self, other): return not self.__eq__(other) def __getattr__(self, item): return self._attributes[item] def __len__(self): return len(self._attributes) def __contains__(self, item): return item in self._attributes def __str__(self): return "" def __repr__(self): return self.__str__() def setdefault(self, key, value): self._attributes.setdefault(key, value) def update(self, values): if isinstance(values, Rule): values = values._attributes self._attributes.update(values) resources/system.py000064400000011233151114232410010446 0ustar00#-*- coding: utf-8 -*- # system.py # Module for getting data about your operating system # Dont worry, only necessary data required for this application. # Tracer *will not* store, collect or send your data anywhere. # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import # WARNING: There are imports in package_manager() import os import pwd import importlib import distro import psutil from sys import version_info from tracer.resources.PackageManager import PackageManager from tracer.resources.processes import Process class System(object): @staticmethod def distribution(): """ Checks if /etc/os-release exists, and if it does, uses it to divine the name of the distribution or distribution like. e.g It will return 'debian' on Ubuntu systems. Otherwise, revert to using distro.id() """ if os.path.isfile("/etc/os-release"): with open("/etc/os-release") as os_release_file: os_release_data = {} distros = ["gentoo", "debian", "rhel", "centos", "ol", "mageia", "arch", "archarm", "fedora", "suse"] # Remove empty lines and trailing spaces lines = [line.rstrip() for line in os_release_file if line.rstrip()] for line in lines: os_release_key, os_release_value = line.split("=") os_release_data[os_release_key] = os_release_value.strip('"') if os_release_data["ID"] in distros: # Special case since centos 7 has only yum, but centos-8 uses dnf if os_release_data["ID"] == "centos" and os_release_data["VERSION_ID"] == 7: return "centos-7" return os_release_data["ID"] else: if "ID_LIKE" in os_release_data: for distribution in os_release_data["ID_LIKE"].split(): if distribution in distros: return distribution else: return distro.id() @staticmethod def package_manager(**kwargs): """Returns instance of package manager according to installed linux distribution""" def get_instance(pair): # WARNING: Imports here path, name = pair module = importlib.import_module(path) return getattr(module, name)(**kwargs) managers = { "gentoo": [("tracer.packageManagers.portage", "Portage")], "debian": [("tracer.packageManagers.dpkg", "Dpkg")], "rhel": [ ("tracer.packageManagers.dnf", "Dnf"), ("tracer.packageManagers.yum", "Yum"), ], "centos": [ ("tracer.packageManagers.dnf", "Dnf"), ("tracer.packageManagers.yum", "Yum"), ], "centos-7": [("tracer.packageManagers.yum", "Yum")], "ol": [ ("tracer.packageManagers.dnf", "Dnf"), ("tracer.packageManagers.yum", "Yum"), ], "mageia": [("tracer.packageManagers.dnf", "Dnf")], "arch": [("tracer.packageManagers.alpm", "Alpm")], "archarm": [("tracer.packageManagers.alpm", "Alpm")], "fedora": [ ("tracer.packageManagers.dnf", "Dnf"), ("tracer.packageManagers.yum", "Yum"), ], "suse": [("tracer.packageManagers.dnf", "Dnf")], } distribution = System.distribution() if distribution not in managers: return None return PackageManager(*list(map(get_instance, managers[distribution]))) @staticmethod def init_system(): """ Returns name of init system you are using e.g. init, systemd, upstart """ init = Process(1) name = init.name().split(" ")[0] return name @staticmethod def boot_time(): # psutil-2.x.x is not backward compatible to psutil-1.x.x try: return psutil.boot_time() except AttributeError: return psutil.get_boot_time() @staticmethod def python_version(): return "{}.{}.{}".format(version_info.major, version_info.minor, version_info.micro) @staticmethod def running_kernel_package(): return System.package_manager().find_package(System.kernel_package_name(), os.uname()[2]) @staticmethod def kernel_package_name(): """ TODO: infer kernel package from current distribution """ return 'kernel' @staticmethod def user(): # getlogin is preferred because it return current username even # if python process is executed with sudo try: return os.getlogin() except OSError: return pwd.getpwuid(os.getuid())[0] resources/tracer.py000064400000016275151114232410010415 0ustar00#-*- coding: utf-8 -*- # tracer.py # Tracer finds outdated running applications in your system # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import absolute_import import os from psutil import NoSuchProcess from tracer.resources.package import Package from tracer.resources.system import System from tracer.resources.FilenameCleaner import FilenameCleaner from tracer.resources.processes import AffectedProcess from tracer.resources.collections import ApplicationsCollection, AffectedProcessesCollection, PackagesCollection from tracer.resources.exceptions import UnsupportedDistribution from tracer.resources.applications import Applications, AffectedApplication from tracer.resources.lang import _ class Tracer(object): """Tracer finds outdated running applications in your system""" """List of packages that only should be traced""" specified_packages = None """ When true, tracer pretends that specified packages have been updated just now. Benefit of this is absolutely no need for openning the package history database """ now = False """ Timestamp since when the updates should be """ timestamp = None """Instance of package manager class. Set by __init__""" _PACKAGE_MANAGER = None """Structure representing all processes and files they use. See ``tracer.resources.memory.dump_memory``""" _memory = None """Objects responsible for providing applications and rules settings form config files""" _rules = None _applications = None """Observer object responsible for calling desired hooks""" _hooks_observer = None """Should tracer find even erased applications?""" _erased = False def __init__(self, package_manager, rules, applications, memory=None, hooks_observer=None, erased=False): if not package_manager: raise UnsupportedDistribution(System.distribution()) self._PACKAGE_MANAGER = package_manager self._rules = rules self._applications = applications self._memory = memory self._hooks_observer = hooks_observer self._erased = erased def _modified_packages(self): """Returns list of packages what tracer should care about""" if self.specified_packages and self.now: return PackagesCollection(self.specified_packages) timestamp = self.timestamp if self.timestamp else System.boot_time() packages = self._PACKAGE_MANAGER.packages_newer_than(timestamp) packages = packages.intersection(self.specified_packages) return packages def trace_affected(self, user=None): """ Returns collection of applications which uses some files that have been modified @TODO This function should be hardly optimized """ memory = self._memory(user) packages = self._modified_packages() affected = {} found = [] for package in packages.unique_newest(): for file in self._PACKAGE_MANAGER.package_files(package.name): file = FilenameCleaner.strip(file) if not file in memory: continue for p in memory[file]: if p.pid in found: continue try: if p.create_time() <= package.modified: found.append(p.pid) p = self._apply_rules(p) a = self._applications.find(p.name()) if not a.ignore: if a.name not in affected: if self._erased and not self._PACKAGE_MANAGER.provided_by(a): a.type = Applications.TYPES["ERASED"] affected[a.name] = AffectedApplication(a._attributes) affected[a.name].affected_instances = AffectedProcessesCollection() self._call_hook(affected[a.name]) affected[a.name].affected_instances.append(p) except NoSuchProcess: pass if not self._applications.find('kernel').ignore and self._has_updated_kernel(): # Add fake AffectedApplication affected['kernel'] = AffectedApplication({"name": "kernel", "type": Applications.TYPES["STATIC"], "helper": _("You will have to reboot your computer")}) return ApplicationsCollection(affected.values()) def _has_updated_kernel(self): running = System.running_kernel_package() if running is None: """ If the running kernel package could not be determined, abort """ return False kernel_package_name = System.kernel_package_name() latest = Package(kernel_package_name) latest.load_info(self._PACKAGE_MANAGER) return self._PACKAGE_MANAGER.compare_packages(running, latest) == -1 def _apply_rules(self, process): parent = process.parent() if not parent: return process c_rule = self._rules.find(process.name()) p_rule = self._rules.find(parent.name()) if c_rule and c_rule.action == self._rules.ACTIONS["RETURN"]: return process if not p_rule or not p_rule.action: return process if p_rule.action == self._rules.ACTIONS["CALL-PARENT"]: return self._apply_rules(parent) # Only RETURN action left # RETURN rule is defined for parent process return parent def _call_hook(self, app): if self._hooks_observer: self._hooks_observer(app.name) def trace_application(self, app, affected_process_factory=AffectedProcess): """ Returns collection of processes where each of them contains packages which affected it. Packages contains only files matching with the particular process """ packages = self._modified_packages() processes = AffectedProcessesCollection() for process in app.instances: processes.update(self._affecting_processes(process, packages, affected_process_factory)) processes.update(self._affecting_children(process, packages, affected_process_factory)) return processes def _affecting_processes(self, process, packages, affected_process_factory=AffectedProcess): collection = AffectedProcessesCollection() process_files = process.files for package in packages: matching_files = set() for package_file in self._PACKAGE_MANAGER.package_files(package.name): package_file = FilenameCleaner.strip(package_file) if not package_file in process_files: continue if process.create_time() <= package.modified: matching_files.add(package_file) if matching_files: aff_pkg = package aff_pkg.files = matching_files affected = affected_process_factory(process.pid) affected.__dict__.update(process.__dict__) affected.packages.update([aff_pkg]) collection.update([affected]) return collection def _affecting_children(self, process, packages, affected_process_factory): if not self._rules.find(process.name()): return {} processes = AffectedProcessesCollection() for child in process.children(): processes.update(self._affecting_processes(child, packages, affected_process_factory)) processes.update(self._affecting_children(child, packages, affected_process_factory)) return processes tests/__pycache__/test_lang.cpython-39.pyc000064400000001251151114232410014520 0ustar00a "e@sHddlTddlmmZddlZGdddejZedkrDe dS))*Nc@seZdZddZdS)TestLangcCs|ttddS)N_)Z assertTruehasattrlang)selfr :/usr/lib/python3.9/site-packages/tracer/tests/test_lang.py test_provide_underscore_functionsz)TestLang.test_provide_underscore_functionN)__name__ __module__ __qualname__r r r r r rsr__main__) Z__meta__Ztracer.resources.langZ resourcesrosZunittestZTestCaserr mainr r r r s tests/__pycache__/test_package.cpython-39.opt-1.pyc000064400000001550151114232410016133 0ustar00a "es@s*ddlTddlmZGdddejZdS))*)Packagec@seZdZddZddZdS) TestPackagecCs4td}td}td}||||||dS)NfooZbar)r assertEqualZassertNotEqual)selfZp1Zp2Zp3r =/usr/lib/python3.9/site-packages/tracer/tests/test_package.py test_equalitys  zTestPackage.test_equalitycCstd}|t|ddS)Nrz )rrrepr)rpackager r r test_representationszTestPackage.test_representationN)__name__ __module__ __qualname__r rr r r r rsrN)Z__meta__Ztracer.resources.packagerZunittestZTestCaserr r r r s tests/__pycache__/test_package.cpython-39.pyc000064400000001550151114232410015174 0ustar00a "es@s*ddlTddlmZGdddejZdS))*)Packagec@seZdZddZddZdS) TestPackagecCs4td}td}td}||||||dS)NfooZbar)r assertEqualZassertNotEqual)selfZp1Zp2Zp3r =/usr/lib/python3.9/site-packages/tracer/tests/test_package.py test_equalitys  zTestPackage.test_equalitycCstd}|t|ddS)Nrz )rrrepr)rpackager r r test_representationszTestPackage.test_representationN)__name__ __module__ __qualname__r rr r r r rsrN)Z__meta__Ztracer.resources.packagerZunittestZTestCaserr r r r s tests/__pycache__/test_portage.cpython-39.opt-1.pyc000064400000004414151114232410016203 0ustar00a "e@snddlTzddlmZddlmZWney6Yn0eedkdGdddej Z e d krje d S) )*)IPackageManager)PortageZgentooz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S) TestPortagecCs t|_dS)N)rmanagerselfr =/usr/lib/python3.9/site-packages/tracer/tests/test_portage.pysetUp szTestPortage.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz5TestPortage.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz/TestPortage.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infosz"TestPortage.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz*TestPortage.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestPortage.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.portager ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_portage.cpython-39.pyc000064400000004414151114232410015244 0ustar00a "e@snddlTzddlmZddlmZWney6Yn0eedkdGdddej Z e d krje d S) )*)IPackageManager)PortageZgentooz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S) TestPortagecCs t|_dS)N)rmanagerselfr =/usr/lib/python3.9/site-packages/tracer/tests/test_portage.pysetUp szTestPortage.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz5TestPortage.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz/TestPortage.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infosz"TestPortage.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz*TestPortage.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestPortage.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.portager ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_processes.cpython-39.opt-1.pyc000064400000005320151114232410016545 0ustar00a "e @sjddlTddlmZmZmZddlmZddlmZddl Z ddl Z Gddde j Z Gd d d eZdS) )*) ProcessesProcessProcessWrapper) SystemdDbus)ProcessesCollectionNc@sdeZdZeddddZeddddZeddddZd d Zeddd d Z d S) TestProcessesTz%@TODO Create Mock for Processes classcCs:td}|}||t|D]}||tq$dS)Nr)rallchildrenZassertIsInstancerr)selfprocessr childr?/usr/lib/python3.9/site-packages/tracer/tests/test_processes.py test_children s   zTestProcesses.test_childrencCs|tt}tt}||tt||||||ttt}| ||| ||dSN) rosgetpidgetppidZassertIsparentZassertInr Z reset_cache assertEqualZ assertIsNot)r r rZprocess2rrrtest_unique_processs    z!TestProcesses.test_unique_processcCsdtt}|tjtjjtjd}| dt || | dt || dS)N)stdinrr) rrrr subprocessPopensys executablePIPErlenZ rebuild_cacheZ terminate)r r rrrrtest_process_caching"s z"TestProcesses.test_process_cachingcCsJt}ddgdd|_t}ddgdd|_t}dddgd|_dS)NZsshd/usr/sbin/sshd)r!z-DZfooZbar)nameZexeZcmdline)ZsomethingandZ argumentsZidkZwhatZ withoutparams) ProcessMockdata)r Zp1Zp2Zp3rrrtest_name_sshd1szTestProcesses.test_name_sshdcCst}t}t|d}dS)Ni)rrpidsmax)r Zdbusr(Z nonexistingrrr test_dbusDs zTestProcesses.test_dbusN) __name__ __module__ __qualname__unittestZskipIfrrr r'r*rrrrr s      r c@seZdZddZddZdS)r%cCs i|_dSrr&)r rrr__init__NszProcessMock.__init__cCs |j|Srr/)r r"rrr_attrQszProcessMock._attrN)r+r,r-r0r1rrrrr%Msr%)Z__meta__Ztracer.resources.processesrrrZtracer.resources.SystemdDbusrZtracer.resources.collectionsrrrr.ZTestCaser r%rrrrs  Dtests/__pycache__/test_processes.cpython-39.pyc000064400000005564151114232410015620 0ustar00a "e @sjddlTddlmZmZmZddlmZddlmZddl Z ddl Z Gddde j Z Gd d d eZdS) )*) ProcessesProcessProcessWrapper) SystemdDbus)ProcessesCollectionNc@sdeZdZeddddZeddddZeddddZd d Zeddd d Z d S) TestProcessesTz%@TODO Create Mock for Processes classcCs:td}|}||t|D]}||tq$dS)Nr)rallchildrenZassertIsInstancerr)selfprocessr childr?/usr/lib/python3.9/site-packages/tracer/tests/test_processes.py test_children s   zTestProcesses.test_childrencCs|tt}tt}||tt||||||ttt}| ||| ||dSN) rosgetpidgetppidZassertIsparentZassertInr Z reset_cache assertEqualZ assertIsNot)r r rZprocess2rrrtest_unique_processs    z!TestProcesses.test_unique_processcCsdtt}|tjtjjtjd}| dt || | dt || dS)N)stdinrr) rrrr subprocessPopensys executablePIPErlenZ rebuild_cacheZ terminate)r r rrrrtest_process_caching"s z"TestProcesses.test_process_cachingcCszt}ddgdd|_|dks(Jt}ddgdd|_|dksPJt}dddgd|_|dksvJdS)NZsshd/usr/sbin/sshd)r!z-DZfooZbar)nameZexeZcmdline)ZsomethingandZ argumentsZidkZwhatzssh-thing-sessionZ withoutparams) ProcessMockdatar")r Zp1Zp2Zp3rrrtest_name_sshd1s"zTestProcesses.test_name_sshdcCsFt}t}t|d}|dddus.J||ddusBJdS)NirZPAMNameF)rrpidsmaxZhas_service_property_from_pid)r Zdbusr(Z nonexistingrrr test_dbusDs  zTestProcesses.test_dbusN) __name__ __module__ __qualname__unittestZskipIfrrr r'r*rrrrr s      r c@seZdZddZddZdS)r%cCs i|_dSrr&)r rrr__init__NszProcessMock.__init__cCs |j|Srr/)r r"rrr_attrQszProcessMock._attrN)r+r,r-r0r1rrrrr%Msr%)Z__meta__Ztracer.resources.processesrrrZtracer.resources.SystemdDbusrZtracer.resources.collectionsrrrr.ZTestCaser r%rrrrs  Dtests/__pycache__/test_query.cpython-39.pyc000064400000002544151114232410014752 0ustar00a "e>@sNddlTddlmZmZGdddejZGdddeZe dkrJe d S) )*)QueryLazyc@seZdZddZddZdS) TestQuerycCsttd|_dS)N)Ztracer)r TracerMockquery)selfr ;/usr/lib/python3.9/site-packages/tracer/tests/test_query.pysetUpszTestQuery.setUpcCsB|j}||t|t|d|t|gddS)NgetABC) rZaffected_applicationsZassertIsInstancerZ assertTruehasattrZassertListEquallistr )r Z apps_queryr r r test_affected_applications s  z$TestQuery.test_affected_applicationsN)__name__ __module__ __qualname__r rr r r r rsrc@seZdZddZdddZdS)rcGsdS)Nr )r argsr r r __init__szTracerMock.__init__NcCsgdS)Nrr )r userr r r trace_affectedszTracerMock.trace_affected)N)rrrrrr r r r rsr__main__N) Z__meta__Z tracer.queryrrZunittestZTestCaserobjectrrmainr r r r s   tests/__pycache__/test_rules.cpython-39.opt-1.pyc000064400000007143151114232410015676 0ustar00a "e@sddlTddlmZddlmZmZzddlmZmZdZ Wn ddl mZmZdZ Yn0Gdd d e j Z ed kre d S) )*)DATA_DIR)RulesRule)patch mock_openz builtins.openz__builtin__.openc@s`eZdZeddZddZddZddZd d Zd d Z d dZ ddZ ddZ ddZ dS) TestRulescCsddtjD|_dS)NcSsg|]}|tr|qS) startswithr.0xr r ;/usr/lib/python3.9/site-packages/tracer/tests/test_rules.py s z(TestRules.setUpClass..)r DEFINITIONS)clsr r r setUpClassszTestRules.setUpClasscCs|jt_dt_dSN)rrZ_rulesselfr r rsetUpszTestRules.setUpcCstD]}||tqdSr)rallZassertIsInstancerrZruler r rtest_rules_typess zTestRules.test_rules_typescCs|d}tD]j}d|vs d|vr2|dt||jtjvrR|d|jt|dkrn|d|j|d7}q dS)NrnameactionzMissing attributes in rule #zUnknown action in rule: z Unsupported attributes in rule: ) rrfailstrrZACTIONSvaluesrlen)rirr r rtest_rules_attributess  zTestRules.test_rules_attributescCs4t}|D]"}||dkr |d|jq dS)NrzDuplicate rules for: )rrcountrr)rrulesr#r r rtest_rules_duplicity*szTestRules.test_rules_duplicitycCs|tddS)NZNON_EXISTING_APPLICATION)Z assertIsNonerfindrr r rtest_app_with_no_rule0szTestRules.test_app_with_no_rulecCs0tddi}|t|d|t|ddS)Nrfooz )r assertEqualrreprrr r rtest_representations3s zTestRules.test_representationscCs8tddd}tddd}||||jddS)Nr*bar)rrZbaz)rupdater+r)rZr1Zr2r r r test_update8s zTestRules.test_updatecCsdgt_d}ttt|dvt}|t|d|tdd|D||dj d||dj d ||d j d Wd n1s0Yd S) z/ Test parsing a single XML file with rules zwhatever-file.xmlzM )Z read_datarcSsg|]}t|tqSr ) isinstancerr r r rrMz'TestRules.test_load..rr*returnrr.N) rrr builtins_openrrr+r!Z assertTruerr)rdatar&r r r test_load?szTestRules.test_loadcCs$d}|D]}|j|kr|d7}q|S)Nrr)r)rZapp_nameZappsr%ar r r_countRs   zTestRules._countN)__name__ __module__ __qualname__ classmethodrrrr$r'r)r-r0r6r8r r r rr s r __main__N)Z__meta__Z tracer.pathsrZtracer.resources.rulesrrZ unittest.mockrrr4ZmockZunittestZTestCaser r9mainr r r rs  Mtests/__pycache__/test_rules.cpython-39.pyc000064400000007143151114232410014737 0ustar00a "e@sddlTddlmZddlmZmZzddlmZmZdZ Wn ddl mZmZdZ Yn0Gdd d e j Z ed kre d S) )*)DATA_DIR)RulesRule)patch mock_openz builtins.openz__builtin__.openc@s`eZdZeddZddZddZddZd d Zd d Z d dZ ddZ ddZ ddZ dS) TestRulescCsddtjD|_dS)NcSsg|]}|tr|qS) startswithr.0xr r ;/usr/lib/python3.9/site-packages/tracer/tests/test_rules.py s z(TestRules.setUpClass..)r DEFINITIONS)clsr r r setUpClassszTestRules.setUpClasscCs|jt_dt_dSN)rrZ_rulesselfr r rsetUpszTestRules.setUpcCstD]}||tqdSr)rallZassertIsInstancerrZruler r rtest_rules_typess zTestRules.test_rules_typescCs|d}tD]j}d|vs d|vr2|dt||jtjvrR|d|jt|dkrn|d|j|d7}q dS)NrnameactionzMissing attributes in rule #zUnknown action in rule: z Unsupported attributes in rule: ) rrfailstrrZACTIONSvaluesrlen)rirr r rtest_rules_attributess  zTestRules.test_rules_attributescCs4t}|D]"}||dkr |d|jq dS)NrzDuplicate rules for: )rrcountrr)rrulesr#r r rtest_rules_duplicity*szTestRules.test_rules_duplicitycCs|tddS)NZNON_EXISTING_APPLICATION)Z assertIsNonerfindrr r rtest_app_with_no_rule0szTestRules.test_app_with_no_rulecCs0tddi}|t|d|t|ddS)Nrfooz )r assertEqualrreprrr r rtest_representations3s zTestRules.test_representationscCs8tddd}tddd}||||jddS)Nr*bar)rrZbaz)rupdater+r)rZr1Zr2r r r test_update8s zTestRules.test_updatecCsdgt_d}ttt|dvt}|t|d|tdd|D||dj d||dj d ||d j d Wd n1s0Yd S) z/ Test parsing a single XML file with rules zwhatever-file.xmlzM )Z read_datarcSsg|]}t|tqSr ) isinstancerr r r rrMz'TestRules.test_load..rr*returnrr.N) rrr builtins_openrrr+r!Z assertTruerr)rdatar&r r r test_load?szTestRules.test_loadcCs$d}|D]}|j|kr|d7}q|S)Nrr)r)rZapp_nameZappsr%ar r r_countRs   zTestRules._countN)__name__ __module__ __qualname__ classmethodrrrr$r'r)r-r0r6r8r r r rr s r __main__N)Z__meta__Z tracer.pathsrZtracer.resources.rulesrrZ unittest.mockrrr4ZmockZunittestZTestCaser r9mainr r r rs  Mtests/__pycache__/test_tracer.cpython-39.opt-1.pyc000064400000012526151114232410016025 0ustar00a "e @sddlTddlmZddlmZddlmZmZddlm Z ddl m Z m Z m Z mZzddlmZWnddlmZYn0Gd d d ejZGd d d eZGd dde ZGdddeZGdddeZGdddeZdddZedkredS))*)Tracer)Rules) Applications Application)AffectedProcess)ProcessesCollectionPackagesCollectionApplicationsCollectionAffectedProcessesCollection)patchc@s0eZdZddZedddddZdd Zd S) TestRulescCs>tt_tttttd|_d|j_t dddt t _ dS)N)memoryiZkernelT)nameignore) r rZ_appsrPackageManagerMockrdump_memory_mocktracerZ timestampZ_append_application ProcessesMockrZprocesses_factoryselfr|j}|t|ttdtdg||tdS)Nbazqux)rZtrace_affectedZassertSetEqualsetrfindassertIsInstancer )rZ init_systemaffectedrrrtest_trace_affecteds $zTestRules.test_trace_affectedcCsV|jtdt}||t|t|d|d}||t ||j ddS)Nrrr) rZtrace_applicationrrAffectedProcessMockrr Z assertEquallenrpid)rr processrrrtest_trace_application s   z TestRules.test_trace_applicationN)__name__ __module__ __qualname__rr r!r'rrrrrs  rc@sXeZdZddZddZeddZeddZed d Zd d Z d dZ ddZ dS) ProcessMockcCs||_||_||_||_dSN)r%files_name _create_time)rr%r create_timer-rrr__init__+szProcessMock.__init__cCs|jSr,r.rrrrr1szProcessMock.namecCs|jSr,r2rrrr real_name4szProcessMock.real_namecCsdSNFrrrrris_interpreted8szProcessMock.is_interpretedcCsdSr4rrrrr is_session<szProcessMock.is_sessioncCs|jSr,)r/rrrrr0@szProcessMock.create_timecCsgSr,rrrrrchildrenCszProcessMock.childrencCsdSr,rrrrrparentFszProcessMock.parentN) r(r)r*r1rpropertyr3r5r6r0r7r8rrrrr+*s   r+c@seZdZdddZdS)r#NcCs||_t|_t|_dSr,)r%rZpackagesr-)rr%rrrr1KszAffectedProcessMock.__init__)Nr(r)r*r1rrrrr#Jsr#c@seZdZeddZdS)rc CsHttdddgdtdddgdtd d d gd td ddddggS)NZfooiWfile1Zfile2file3Zbari'Zfile10Zfile11Zfile12r"ri )file7r=r>rafile4file9)r r+rrrrallSs zProcessesMock.allN)r(r)r* staticmethodrFrrrrrRsrc@seZdZddZdS) PackageMockcCs||_||_||_dSr,)rmodifiedr-)rrrIr-rrrr1^szPackageMock.__init__Nr:rrrrrH]srHc@sXeZdZeddgdeddgdeddgd ed d gd gZd dZddZdS)rAi r<Bi\)rDZfile5Zfile6CrC)rAZfile8rEDi"r@csttfdd|jS)Ncs |jkSr,)rI)p unix_timerrmz8PackageManagerMock.packages_newer_than..)r filter _packages)rrPrrOrpackages_newer_thanlsz&PackageManagerMock.packages_newer_thancCs$|jD]}|j|kr|jSqdSr,)rTrr-)rpkg_namepackagerrr package_filesos  z PackageManagerMock.package_filesN)r(r)r*rHrTrUrXrrrrrdsrNcCsDi}tD]2}|jD]&}||vr2|||q|g||<qq |Sr,)rrFr-append)userrr&filerrrrus  r__main__)N)Z__meta__Ztracer.resources.tracerrZtracer.resources.rulesrZtracer.resources.applicationsrrZtracer.resources.processesrZtracer.resources.collectionsr r r r Z unittest.mockr ZmockZunittestZTestCaserobjectr+r#rrHrrr(mainrrrrs$      tests/__pycache__/test_tracer.cpython-39.pyc000064400000012526151114232410015066 0ustar00a "e @sddlTddlmZddlmZddlmZmZddlm Z ddl m Z m Z m Z mZzddlmZWnddlmZYn0Gd d d ejZGd d d eZGd dde ZGdddeZGdddeZGdddeZdddZedkredS))*)Tracer)Rules) Applications Application)AffectedProcess)ProcessesCollectionPackagesCollectionApplicationsCollectionAffectedProcessesCollection)patchc@s0eZdZddZedddddZdd Zd S) TestRulescCs>tt_tttttd|_d|j_t dddt t _ dS)N)memoryiZkernelT)nameignore) r rZ_appsrPackageManagerMockrdump_memory_mocktracerZ timestampZ_append_application ProcessesMockrZprocesses_factoryselfr|j}|t|ttdtdg||tdS)Nbazqux)rZtrace_affectedZassertSetEqualsetrfindassertIsInstancer )rZ init_systemaffectedrrrtest_trace_affecteds $zTestRules.test_trace_affectedcCsV|jtdt}||t|t|d|d}||t ||j ddS)Nrrr) rZtrace_applicationrrAffectedProcessMockrr Z assertEquallenrpid)rr processrrrtest_trace_application s   z TestRules.test_trace_applicationN)__name__ __module__ __qualname__rr r!r'rrrrrs  rc@sXeZdZddZddZeddZeddZed d Zd d Z d dZ ddZ dS) ProcessMockcCs||_||_||_||_dSN)r%files_name _create_time)rr%r create_timer-rrr__init__+szProcessMock.__init__cCs|jSr,r.rrrrr1szProcessMock.namecCs|jSr,r2rrrr real_name4szProcessMock.real_namecCsdSNFrrrrris_interpreted8szProcessMock.is_interpretedcCsdSr4rrrrr is_session<szProcessMock.is_sessioncCs|jSr,)r/rrrrr0@szProcessMock.create_timecCsgSr,rrrrrchildrenCszProcessMock.childrencCsdSr,rrrrrparentFszProcessMock.parentN) r(r)r*r1rpropertyr3r5r6r0r7r8rrrrr+*s   r+c@seZdZdddZdS)r#NcCs||_t|_t|_dSr,)r%rZpackagesr-)rr%rrrr1KszAffectedProcessMock.__init__)Nr(r)r*r1rrrrr#Jsr#c@seZdZeddZdS)rc CsHttdddgdtdddgdtd d d gd td ddddggS)NZfooiWfile1Zfile2file3Zbari'Zfile10Zfile11Zfile12r"ri )file7r=r>rafile4file9)r r+rrrrallSs zProcessesMock.allN)r(r)r* staticmethodrFrrrrrRsrc@seZdZddZdS) PackageMockcCs||_||_||_dSr,)rmodifiedr-)rrrIr-rrrr1^szPackageMock.__init__Nr:rrrrrH]srHc@sXeZdZeddgdeddgdeddgd ed d gd gZd dZddZdS)rAi r<Bi\)rDZfile5Zfile6CrC)rAZfile8rEDi"r@csttfdd|jS)Ncs |jkSr,)rI)p unix_timerrmz8PackageManagerMock.packages_newer_than..)r filter _packages)rrPrrOrpackages_newer_thanlsz&PackageManagerMock.packages_newer_thancCs$|jD]}|j|kr|jSqdSr,)rTrr-)rpkg_namepackagerrr package_filesos  z PackageManagerMock.package_filesN)r(r)r*rHrTrUrXrrrrrdsrNcCsDi}tD]2}|jD]&}||vr2|||q|g||<qq |Sr,)rrFr-append)userrr&filerrrrus  r__main__)N)Z__meta__Ztracer.resources.tracerrZtracer.resources.rulesrZtracer.resources.applicationsrrZtracer.resources.processesrZtracer.resources.collectionsr r r r Z unittest.mockr ZmockZunittestZTestCaserobjectr+r#rrHrrr(mainrrrrs$      tests/__pycache__/test_views.cpython-39.opt-1.pyc000064400000021337151114232410015702 0ustar00a "e@'@s&ddlmZddlTddlmZddlmZddlmZddl m Z m Z ddl m Z dd lmZdd lmZmZdd lZdd lZdd lZdd lZejd d dgdZejZzddlmZWnddlmZYn0eejj_eejj_eejj _Gddde!j"Z#Gddde$Z%Gddde$Zd S))unicode_literals)*)StringIO) DefaultView) HelperView) Applications Application)ApplicationsCollection)Package) ProcessMockAffectedProcessMockNtracerTen)fallback languages)patchc@sxeZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ edddddZdS) TestViewscCs t|_dSN)routselfr;/usr/lib/python3.9/site-packages/tracer/tests/test_views.pysetUp#szTestViews.setUpcCsFt|j}|dt|dtg|||jddS)Nargs applications)rrassignArgsMockr render assertEqualgetvaluerviewrrrtest_default_none&s  zTestViews.test_default_nonec Cspt|j}|dt|dttddddtddddtdd d dg|||jd dS) Nrr application first helperfirsttypehelpername second helpersecond third helperthirdzkYou should restart: * Some applications using: first helper second helper third helper rrrrr r r r!r"r#rrrtest_default_with_helpers-s  z#TestViews.test_default_with_helpersc Cspt|j}|dt|dttddddtddddtddddg|||jddS) Nrrr&foor*r,r+barbazzSYou should restart: * These applications manually: bar baz foo r1r#rrrtest_default_without_helpers>s  z&TestViews.test_default_without_helperscCst|j}|dt|dttddddtddddtdd d dtdd dd tdd dd tdddd g|||jddS)Nrrr&r'r(r)r-r.r/r0r3r4r5r6zYou should restart: * Some applications using: first helper second helper third helper * These applications manually: bar baz foo r1r#rrr!test_default_with_without_helpersOs  z+TestViews.test_default_with_without_helpersc Cstt|j}|dtdd|dttddddtdd d dtdd d dg|||jd dS)NrTallrsessionr3h1r4r5h2r6h3zbYou should restart: * These applications restarting your session: bar baz foo r1r#rrrtest_default_all_sessionhs  z"TestViews.test_default_all_sessionc Cstt|j}|dtdd|dttddddtdd d dtdd d dg|||jd dS)NrTr9rstaticr3r<r4r5r=r6r>zbYou should restart: * These applications rebooting your computer: bar baz foo r1r#rrrtest_default_all_staticys  z!TestViews.test_default_all_staticcCst|j}|dtdd|dttddddtdd d dtdd d dtd dddtd dddtd dddg|||jddS)NrTr9rr;r3r<r4r5r=r6r>r@aaah4bbbZh5ZcccZh6zYou should restart: * These applications restarting your session: bar baz foo * These applications rebooting your computer: aaa bbb ccc r1r#rrrtest_default_all_session_statics  z)TestViews.test_default_all_session_staticcCst|j}|dtdd|dttddddtdd d dtdd dd tdd dd tdddd tdddd tdddd tdddd g|||jddS)NrTr9rr&r'r(r)r-r.r3r4r5r;r6r<quxr=r@rBr>rDrCaYou should restart: * Some applications using: first helper second helper * These applications manually: bar foo * These applications restarting your session: baz qux * These applications rebooting your computer: aaa bbb r1r#rrrtest_default_alls    zTestViews.test_default_allcCst|j}|dt|dttddddtddddtdd dd tdd dd td d dd td ddd tdddd g|||jddS)Nrrr&r'r(r)r-r.r3r4r5r;r6r<rFr=r@rBr>a!You should restart: * Some applications using: first helper second helper * These applications manually: bar foo Additionally, there are: - 2 processes requiring restart of your session (i.e. Logging out & Logging in again) - 1 processes requiring reboot r1r#rrrtest_default_not_alls   zTestViews.test_default_not_allc Cspt|j}|dt|dttddddtddddtd d d dg|||jd dS) Nrrr;r3r<r4r5r=r@r6r>zThere are: - 2 processes requiring restart of your session (i.e. Logging out & Logging in again) - 1 processes requiring reboot r1r#rrrtest_default_note_onlys  z TestViews.test_default_note_onlyz0tracer.resources.applications.System.init_systemZdummy)Z return_valuecCstdddddgtdddddgg}td }d|_d |_d |_ddg|_td}t|g|_|g}t |j }| d t dd | d|| dt d| d|| d|| dd|||j ddS)Nr3iZfile1Zfile2i.Zfile3Z foopackagezFoo package descriptionZcategr)verbose processesr&package affected_byZaffectsa;* foo Package: foopackage Description: Foo package description Type: Application State: foo has been started by None some-time ago. PID - 2 foo has been started by None some-time ago. PID - 3 Affected by: foopackage file1 file2 )r r Zmodified descriptioncategoryfilesr setZpackagesrrrrrfindr r!r")rZ init_systemrMrNZa1rOr$rrr test_helpers,        zTestViews.test_helperN)__name__ __module__ __qualname__rr%r2r7r8r?rArErGrHrIrrUrrrrr!s! rc@seZdZdZZdddZdS)rNFcCs||_||_||_||_dSr)r:quietuserrL)rr:rYrZrLrrr__init__szArgsMock.__init__)FFFF)rVrWrXr:rYr[rrrrrsrc@s4eZdZddZddZddZddZd d Zd S) r cCs(d|_||_||_||_||_d|_dS)Nz some-time)parentpidrR_name _create_timeZstr_started_ago)rr]r, create_timerRrrrr["s zProcessMock.__init__cCs|jSr)r^rrrrr,*szProcessMock.namecCs|jSr)r_rrrrr`-szProcessMock.create_timecCsgSrrrrrrchildren0szProcessMock.childrencCsdSrrrrrrusername3szProcessMock.usernameN)rVrWrXr[r,r`rarbrrrrr !s r )&Z __future__rZ__meta__Ztracer.resources.pycomprZtracer.views.defaultrZtracer.views.helperrZtracer.resources.applicationsrr Ztracer.resources.collectionsr Ztracer.resources.packager Z test_tracerr r rZtracer.views.note_for_hiddengettext translationtZugettext_Z unittest.mockrZmockZviewsdefaultr+Znote_for_hiddenZunittestZTestCaserobjectrrrrrs2         w tests/__pycache__/test_views.cpython-39.pyc000064400000021337151114232410014743 0ustar00a "e@'@s&ddlmZddlTddlmZddlmZddlmZddl m Z m Z ddl m Z dd lmZdd lmZmZdd lZdd lZdd lZdd lZejd d dgdZejZzddlmZWnddlmZYn0eejj_eejj_eejj _Gddde!j"Z#Gddde$Z%Gddde$Zd S))unicode_literals)*)StringIO) DefaultView) HelperView) Applications Application)ApplicationsCollection)Package) ProcessMockAffectedProcessMockNtracerTen)fallback languages)patchc@sxeZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ edddddZdS) TestViewscCs t|_dSN)routselfr;/usr/lib/python3.9/site-packages/tracer/tests/test_views.pysetUp#szTestViews.setUpcCsFt|j}|dt|dtg|||jddS)Nargs applications)rrassignArgsMockr render assertEqualgetvaluerviewrrrtest_default_none&s  zTestViews.test_default_nonec Cspt|j}|dt|dttddddtddddtdd d dg|||jd dS) Nrr application first helperfirsttypehelpername second helpersecond third helperthirdzkYou should restart: * Some applications using: first helper second helper third helper rrrrr r r r!r"r#rrrtest_default_with_helpers-s  z#TestViews.test_default_with_helpersc Cspt|j}|dt|dttddddtddddtddddg|||jddS) Nrrr&foor*r,r+barbazzSYou should restart: * These applications manually: bar baz foo r1r#rrrtest_default_without_helpers>s  z&TestViews.test_default_without_helperscCst|j}|dt|dttddddtddddtdd d dtdd dd tdd dd tdddd g|||jddS)Nrrr&r'r(r)r-r.r/r0r3r4r5r6zYou should restart: * Some applications using: first helper second helper third helper * These applications manually: bar baz foo r1r#rrr!test_default_with_without_helpersOs  z+TestViews.test_default_with_without_helpersc Cstt|j}|dtdd|dttddddtdd d dtdd d dg|||jd dS)NrTallrsessionr3h1r4r5h2r6h3zbYou should restart: * These applications restarting your session: bar baz foo r1r#rrrtest_default_all_sessionhs  z"TestViews.test_default_all_sessionc Cstt|j}|dtdd|dttddddtdd d dtdd d dg|||jd dS)NrTr9rstaticr3r<r4r5r=r6r>zbYou should restart: * These applications rebooting your computer: bar baz foo r1r#rrrtest_default_all_staticys  z!TestViews.test_default_all_staticcCst|j}|dtdd|dttddddtdd d dtdd d dtd dddtd dddtd dddg|||jddS)NrTr9rr;r3r<r4r5r=r6r>r@aaah4bbbZh5ZcccZh6zYou should restart: * These applications restarting your session: bar baz foo * These applications rebooting your computer: aaa bbb ccc r1r#rrrtest_default_all_session_statics  z)TestViews.test_default_all_session_staticcCst|j}|dtdd|dttddddtdd d dtdd dd tdd dd tdddd tdddd tdddd tdddd g|||jddS)NrTr9rr&r'r(r)r-r.r3r4r5r;r6r<quxr=r@rBr>rDrCaYou should restart: * Some applications using: first helper second helper * These applications manually: bar foo * These applications restarting your session: baz qux * These applications rebooting your computer: aaa bbb r1r#rrrtest_default_alls    zTestViews.test_default_allcCst|j}|dt|dttddddtddddtdd dd tdd dd td d dd td ddd tdddd g|||jddS)Nrrr&r'r(r)r-r.r3r4r5r;r6r<rFr=r@rBr>a!You should restart: * Some applications using: first helper second helper * These applications manually: bar foo Additionally, there are: - 2 processes requiring restart of your session (i.e. Logging out & Logging in again) - 1 processes requiring reboot r1r#rrrtest_default_not_alls   zTestViews.test_default_not_allc Cspt|j}|dt|dttddddtddddtd d d dg|||jd dS) Nrrr;r3r<r4r5r=r@r6r>zThere are: - 2 processes requiring restart of your session (i.e. Logging out & Logging in again) - 1 processes requiring reboot r1r#rrrtest_default_note_onlys  z TestViews.test_default_note_onlyz0tracer.resources.applications.System.init_systemZdummy)Z return_valuecCstdddddgtdddddgg}td }d|_d |_d |_ddg|_td}t|g|_|g}t |j }| d t dd | d|| dt d| d|| d|| dd|||j ddS)Nr3iZfile1Zfile2i.Zfile3Z foopackagezFoo package descriptionZcategr)verbose processesr&package affected_byZaffectsa;* foo Package: foopackage Description: Foo package description Type: Application State: foo has been started by None some-time ago. PID - 2 foo has been started by None some-time ago. PID - 3 Affected by: foopackage file1 file2 )r r Zmodified descriptioncategoryfilesr setZpackagesrrrrrfindr r!r")rZ init_systemrMrNZa1rOr$rrr test_helpers,        zTestViews.test_helperN)__name__ __module__ __qualname__rr%r2r7r8r?rArErGrHrIrrUrrrrr!s! rc@seZdZdZZdddZdS)rNFcCs||_||_||_||_dSr)r:quietuserrL)rr:rYrZrLrrr__init__szArgsMock.__init__)FFFF)rVrWrXr:rYr[rrrrrsrc@s4eZdZddZddZddZddZd d Zd S) r cCs(d|_||_||_||_||_d|_dS)Nz some-time)parentpidrR_name _create_timeZstr_started_ago)rr]r, create_timerRrrrr["s zProcessMock.__init__cCs|jSr)r^rrrrr,*szProcessMock.namecCs|jSr)r_rrrrr`-szProcessMock.create_timecCsgSrrrrrrchildren0szProcessMock.childrencCsdSrrrrrrusername3szProcessMock.usernameN)rVrWrXr[r,r`rarbrrrrr !s r )&Z __future__rZ__meta__Ztracer.resources.pycomprZtracer.views.defaultrZtracer.views.helperrZtracer.resources.applicationsrr Ztracer.resources.collectionsr Ztracer.resources.packager Z test_tracerr r rZtracer.views.note_for_hiddengettext translationtZugettext_Z unittest.mockrZmockZviewsdefaultr+Znote_for_hiddenZunittestZTestCaserobjectrrrrrs2         w tests/__pycache__/test_yum.cpython-39.opt-1.pyc000064400000004344151114232410015356 0ustar00a "e @snddlTzddlmZddlmZWney6Yn0eedkdGdddej Z e d krje d S) )*)IPackageManager)YumZfedoraz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestYumcCs t|_dS)N)rmanagerselfr 9/usr/lib/python3.9/site-packages/tracer/tests/test_yum.pysetUp sz TestYum.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz1TestYum.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz+TestYum.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestYum.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz&TestYum.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestYum.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.yumr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_yum.cpython-39.pyc000064400000004344151114232410014417 0ustar00a "e @snddlTzddlmZddlmZWney6Yn0eedkdGdddej Z e d krje d S) )*)IPackageManager)YumZfedoraz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestYumcCs t|_dS)N)rmanagerselfr 9/usr/lib/python3.9/site-packages/tracer/tests/test_yum.pysetUp sz TestYum.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz1TestYum.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz+TestYum.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestYum.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz&TestYum.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestYum.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.yumr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/__init__.cpython-39.opt-1.pyc000064400000000224151114232410015235 0ustar00a "e@sdS)Nrrr9/usr/lib/python3.9/site-packages/tracer/tests/__init__.pytests/__pycache__/__init__.cpython-39.pyc000064400000000224151114232410014276 0ustar00a "e@sdS)Nrrr9/usr/lib/python3.9/site-packages/tracer/tests/__init__.pytests/__pycache__/__meta__.cpython-39.opt-1.pyc000064400000000601151114232410015217 0ustar00a "e&@s\ddlZejejejeZejjdeddlZddlZddl m Z e Z dS)N)System) ospathdirnamerealpath__file__Z parentdirsysinsertZunittestZtracer.resources.systemrZ distributionZDISTROr r 9/usr/lib/python3.9/site-packages/tracer/tests/__meta__.pys  tests/__pycache__/__meta__.cpython-39.pyc000064400000000601151114232410014260 0ustar00a "e&@s\ddlZejejejeZejjdeddlZddlZddl m Z e Z dS)N)System) ospathdirnamerealpath__file__Z parentdirsysinsertZunittestZtracer.resources.systemrZ distributionZDISTROr r 9/usr/lib/python3.9/site-packages/tracer/tests/__meta__.pys  tests/__pycache__/test_FilenameCleaner.cpython-39.opt-1.pyc000064400000002362151114232410017554 0ustar00a "e@s,ddlmZddlmZGdddeZdS))TestCase)FilenameCleanerc@seZdZddZddZdS)TestFilenameCleanercCs t|_dS)N)rcleanerselfrE/usr/lib/python3.9/site-packages/tracer/tests/test_FilenameCleaner.pysetUpszTestFilenameCleaner.setUpcCs|d|jd|d|jd|d|jd|d|jd|d|jd|d |jd |d |jd dS) Nz /lib/libdl.soz/lib/libdl-2.19.soz/lib/libncurses.soz/lib/libncurses.so.5.9z /bin/bashz%/usr/share/wicd/curses/wicd-curses.pyz /usr/bin/gvimz/usr/bin/gvim#new (deleted)z)/usr/lib64/kde4/kded_networkmanagement.soz2/usr/lib64/kde4/kded_networkmanagement.so;53c7cd86z#/usr/lib64/firefox/plugin-containerz>/usr/lib64/firefox/plugin-container.#prelink#.N3n7Rk (deleted))Z assertEqualrstriprrrr test_strip s  zTestFilenameCleaner.test_stripN)__name__ __module__ __qualname__r r rrrr rsrN)ZunittestrZ tracer.resources.FilenameCleanerrrrrrr s  tests/__pycache__/test_FilenameCleaner.cpython-39.pyc000064400000002362151114232410016615 0ustar00a "e@s,ddlmZddlmZGdddeZdS))TestCase)FilenameCleanerc@seZdZddZddZdS)TestFilenameCleanercCs t|_dS)N)rcleanerselfrE/usr/lib/python3.9/site-packages/tracer/tests/test_FilenameCleaner.pysetUpszTestFilenameCleaner.setUpcCs|d|jd|d|jd|d|jd|d|jd|d|jd|d |jd |d |jd dS) Nz /lib/libdl.soz/lib/libdl-2.19.soz/lib/libncurses.soz/lib/libncurses.so.5.9z /bin/bashz%/usr/share/wicd/curses/wicd-curses.pyz /usr/bin/gvimz/usr/bin/gvim#new (deleted)z)/usr/lib64/kde4/kded_networkmanagement.soz2/usr/lib64/kde4/kded_networkmanagement.so;53c7cd86z#/usr/lib64/firefox/plugin-containerz>/usr/lib64/firefox/plugin-container.#prelink#.N3n7Rk (deleted))Z assertEqualrstriprrrr test_strip s  zTestFilenameCleaner.test_stripN)__name__ __module__ __qualname__r r rrrr rsrN)ZunittestrZ tracer.resources.FilenameCleanerrrrrrr s  tests/__pycache__/test_alpm.cpython-39.opt-1.pyc000064400000004375151114232410015501 0ustar00a "e&@svddlTzddlmZddlmZWney6Yn0eedkoJedkdGdd d ej Z e d krre d S) )*)IPackageManager)AlpmZarchZarcharmz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestAlpmcCs t|_dS)N)rmanagerselfr :/usr/lib/python3.9/site-packages/tracer/tests/test_alpm.pysetUp szTestAlpm.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz2TestAlpm.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz,TestAlpm.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestAlpm.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz'TestAlpm.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestAlpm.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.alpmr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_alpm.cpython-39.pyc000064400000004375151114232410014542 0ustar00a "e&@svddlTzddlmZddlmZWney6Yn0eedkoJedkdGdd d ej Z e d krre d S) )*)IPackageManager)AlpmZarchZarcharmz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestAlpmcCs t|_dS)N)rmanagerselfr :/usr/lib/python3.9/site-packages/tracer/tests/test_alpm.pysetUp szTestAlpm.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz2TestAlpm.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz,TestAlpm.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestAlpm.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz'TestAlpm.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestAlpm.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.alpmr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_applications.cpython-39.opt-1.pyc000064400000012500151114232410017223 0ustar00a "e@sddlTddlmZddlmZmZddlmZmZzddl m Z m Z dZ Wn ddl m Z m Z dZ Yn0Gd d d ejZed kred S) )*)DATA_DIR) Applications Application)ApplicationsCollectionProcessesCollection)patch mock_openz builtins.openz__builtin__.openc@seZdZeddZddZddZddZd d Zd d Z e d ddddZ ddZ ddZ ddZddZe dddddZddZd S)!TestApplicationscCsddtjD|_dS)NcSsg|]}|tr|qS) startswithr.0xr r B/usr/lib/python3.9/site-packages/tracer/tests/test_applications.py s z/TestApplications.setUpClass..)r DEFINITIONS)clsr r r setUpClassszTestApplications.setUpClasscCs|jt_dt_dSN)rrZ_appsselfr r rsetUpszTestApplications.setUpcCs|ttdSr)assertIsInstancerallrrr r rtest_apps_typessz TestApplications.test_apps_typescCstd}||jtdS)Nr)rrrZ instancesr)r applicationr r rtest_application_processess z+TestApplications.test_application_processescCsd}tD]}d|vs$t|dkr6|dt|d|vr^|jtjvr^|d|jd|vrjdnd}|t||d |j |d7}q dS) NrnamezMissing name in definition #typezUnknown type in application: rename)Application {0} has unsupported attribute) rrlenfailstrr ZTYPESvalues assertEqualformatr)rianr r rtest_apps_attributes s z%TestApplications.test_apps_attributescCs8t}|D]&}||j|dkr |d|jq dS)NrzDuplicate definitions for: )rr_countrr&)rappsr,r r rtest_apps_duplicity.sz$TestApplications.test_apps_duplicityz0tracer.resources.applications.System.init_systemZdummy)Z return_valuecCsfd}t|}||j|||jtj||jd||jd|t|dd |jdS)NZNON_EXISTING_APPLICATIONr#r$) rfindr)rr Z DEFAULT_TYPEhelperZnoter%r*)rZ init_systemapp_nameZappr r rtest_app_with_no_definition4s z,TestApplications.test_app_with_no_definitioncCs0tddi}|t|d|t|ddS)Nrfooz)rr)r'repr)rZruler r rtest_representations>s z%TestApplications.test_representationscCs<tdddd}tdddd}||j||jdS)Nr6 applicaiton some helperrr r3rz some helper with {NAME} argument)r assertFalsehelper_contains_name assertTrue)ra1Za2r r rtest_contains_nameCs z#TestApplications.test_contains_namecCs<tdddd}tdddd}||j||jdS)Nr6r9r:r;rzsome helper with {FOO} argument)rr<helper_contains_formatingr>)rr?a3r r rtest_contains_formatingIs z(TestApplications.test_contains_formatingcCs,tdddd}||j||jdS)Nr6r9r;)rr<rAr=)rr?r r rtest_helper_contains_when_noneOs z/TestApplications.test_helper_contains_when_nonez*tracer.resources.system.System.init_systemZsystemdcCsdgt_d}ttt|dt}|t|d|tdd|D||dj d||dj d ||d j d | d |d j Wd n1s0Yd S)z6 Test parsing a single XML file with applications zwhatever-file.xmlz )Z read_datacSsg|]}t|tqSr ) isinstancerrr r rrfz.TestApplications.test_load..rr6zsystemctl restart fooZsessionzkill itN)rrr builtins_openr rr)r%r>rr3endswithr ZassertIn)rZ _init_systemdatar0r r r test_loadTs zTestApplications.test_loadcCs$d}|D]}|j|kr|d7}q|S)Nrr)r)rr4r0countr,r r rr/ls   zTestApplications._countN)__name__ __module__ __qualname__ classmethodrrrrr.r1r r5r8r@rCrDrLr/r r r rr s      r __main__N)Z__meta__Z tracer.pathsrZtracer.resources.applicationsrrZtracer.resources.collectionsrrZ unittest.mockr r rIZmockZunittestZTestCaser rNmainr r r rs  ftests/__pycache__/test_applications.cpython-39.pyc000064400000012500151114232410016264 0ustar00a "e@sddlTddlmZddlmZmZddlmZmZzddl m Z m Z dZ Wn ddl m Z m Z dZ Yn0Gd d d ejZed kred S) )*)DATA_DIR) Applications Application)ApplicationsCollectionProcessesCollection)patch mock_openz builtins.openz__builtin__.openc@seZdZeddZddZddZddZd d Zd d Z e d ddddZ ddZ ddZ ddZddZe dddddZddZd S)!TestApplicationscCsddtjD|_dS)NcSsg|]}|tr|qS) startswithr.0xr r B/usr/lib/python3.9/site-packages/tracer/tests/test_applications.py s z/TestApplications.setUpClass..)r DEFINITIONS)clsr r r setUpClassszTestApplications.setUpClasscCs|jt_dt_dSN)rrZ_appsselfr r rsetUpszTestApplications.setUpcCs|ttdSr)assertIsInstancerallrrr r rtest_apps_typessz TestApplications.test_apps_typescCstd}||jtdS)Nr)rrrZ instancesr)r applicationr r rtest_application_processess z+TestApplications.test_application_processescCsd}tD]}d|vs$t|dkr6|dt|d|vr^|jtjvr^|d|jd|vrjdnd}|t||d |j |d7}q dS) NrnamezMissing name in definition #typezUnknown type in application: rename)Application {0} has unsupported attribute) rrlenfailstrr ZTYPESvalues assertEqualformatr)rianr r rtest_apps_attributes s z%TestApplications.test_apps_attributescCs8t}|D]&}||j|dkr |d|jq dS)NrzDuplicate definitions for: )rr_countrr&)rappsr,r r rtest_apps_duplicity.sz$TestApplications.test_apps_duplicityz0tracer.resources.applications.System.init_systemZdummy)Z return_valuecCsfd}t|}||j|||jtj||jd||jd|t|dd |jdS)NZNON_EXISTING_APPLICATIONr#r$) rfindr)rr Z DEFAULT_TYPEhelperZnoter%r*)rZ init_systemapp_nameZappr r rtest_app_with_no_definition4s z,TestApplications.test_app_with_no_definitioncCs0tddi}|t|d|t|ddS)Nrfooz)rr)r'repr)rZruler r rtest_representations>s z%TestApplications.test_representationscCs<tdddd}tdddd}||j||jdS)Nr6 applicaiton some helperrr r3rz some helper with {NAME} argument)r assertFalsehelper_contains_name assertTrue)ra1Za2r r rtest_contains_nameCs z#TestApplications.test_contains_namecCs<tdddd}tdddd}||j||jdS)Nr6r9r:r;rzsome helper with {FOO} argument)rr<helper_contains_formatingr>)rr?a3r r rtest_contains_formatingIs z(TestApplications.test_contains_formatingcCs,tdddd}||j||jdS)Nr6r9r;)rr<rAr=)rr?r r rtest_helper_contains_when_noneOs z/TestApplications.test_helper_contains_when_nonez*tracer.resources.system.System.init_systemZsystemdcCsdgt_d}ttt|dt}|t|d|tdd|D||dj d||dj d ||d j d | d |d j Wd n1s0Yd S)z6 Test parsing a single XML file with applications zwhatever-file.xmlz )Z read_datacSsg|]}t|tqSr ) isinstancerrr r rrfz.TestApplications.test_load..rr6zsystemctl restart fooZsessionzkill itN)rrr builtins_openr rr)r%r>rr3endswithr ZassertIn)rZ _init_systemdatar0r r r test_loadTs zTestApplications.test_loadcCs$d}|D]}|j|kr|d7}q|S)Nrr)r)rr4r0countr,r r rr/ls   zTestApplications._countN)__name__ __module__ __qualname__ classmethodrrrrr.r1r r5r8r@rCrDrLr/r r r rr s      r __main__N)Z__meta__Z tracer.pathsrZtracer.resources.applicationsrrZtracer.resources.collectionsrrZ unittest.mockr r rIZmockZunittestZTestCaser rNmainr r r rs  ftests/__pycache__/test_collections.cpython-39.opt-1.pyc000064400000007473151114232410017070 0ustar00a "e @sbddlTddlmZmZddlmZmZddlmZddl m Z m Z m Z m Z GdddejZd S) )*) Applications Application) ProcessesAffectedProcess)Package)ApplicationsCollectionProcessesCollectionPackagesCollectionAffectedProcessesCollectionc@sXeZdZddZddZddZeddd d Zd d Z d dZ ddZ ddZ dS)TestCollectionscCstj}tdd|d}tdd|d}tdd|d}t|||g}||dt|||g||d t|||g||tdS) NfoobarnamehelpertypebazquxZquuxZcorgerr)r DEFAULT_TYPErr assertEqualsortedassertIsInstance)self default_typea1a2a3 collectionr A/usr/lib/python3.9/site-packages/tracer/tests/test_collections.pytest_applications_sorted sz(TestCollections.test_applications_sortedcCs<t}||t||dt||dtdS)NusergffA)rallrr owned_byZ newer_thanrrr r r!test_processes_typess z$TestCollections.test_processes_typescCs"td}|t|ddS)Nr)rr$r%Z assertGreaterlenr&r r r!test_processes_none_usersz(TestCollections.test_processes_none_userTz%@TODO Create Mock for Processes classcCsdtd}td}tgd|_t}||g||g||||d|||jdS)Ni)rrrr)rsetfilesr updateZassertInindex)rp1p2cr r r!test_processes_updates   z%TestCollections.test_processes_updatecCstd}td}td}tdd}td}t||||g}||||gdt||gd||d||||gdjdS)Nrrrr{rr)rr r intersectionrZassertIsNotNoneZmodified)rr.r/Zp3Zp4Zp5c1r r r!test_packages_intersection,s *z*TestCollections.test_packages_intersectioncCsDtddi}tddi}tddi}t|||g}|ddddS)Nrrrrr)rr Zreplace_values)rrrrr4r r r!test_replace_values7s    z#TestCollections.test_replace_valuescCsPt}|d}tt|dD](}||||dkr"tdq"dS)N create_timerz$The collection isn't sorted properly)rr$rranger(r7 Exception)rr4Zc2ir r r!test_collection_sorted_callableAs  z/TestCollections.test_collection_sorted_callablecCsZtj}tdd|d}tdd|d}t||g}|d}|dd|DddgdS) za https://github.com/FrostyX/tracer/issues/151 https://github.com/FrostyX/tracer/issues/156 rNrrrrcSsg|] }|jqSr )r).0Zappr r r! SzGTestCollections.test_application_sorted_none_helper..)rrrr rr)rrrrrZcollection_sortedr r r!#test_application_sorted_none_helperIs  z3TestCollections.test_application_sorted_none_helperN) __name__ __module__ __qualname__r"r'r)unittestZskipIfr1r5r6r;r?r r r r!r s     r N)Z__meta__Ztracer.resources.applicationsrrZtracer.resources.processesrrZtracer.resources.packagerZtracer.resources.collectionsr r r r rCZTestCaser r r r r!s  tests/__pycache__/test_collections.cpython-39.pyc000064400000010226151114232410016117 0ustar00a "e @sbddlTddlmZmZddlmZmZddlmZddl m Z m Z m Z m Z GdddejZd S) )*) Applications Application) ProcessesAffectedProcess)Package)ApplicationsCollectionProcessesCollectionPackagesCollectionAffectedProcessesCollectionc@sXeZdZddZddZddZeddd d Zd d Z d dZ ddZ ddZ dS)TestCollectionscCstj}tdd|d}tdd|d}tdd|d}t|||g}||dt|||g||d t|||g||tdS) NfoobarnamehelpertypebazquxZquuxZcorgerr)r DEFAULT_TYPErr assertEqualsortedassertIsInstance)self default_typea1a2a3 collectionr A/usr/lib/python3.9/site-packages/tracer/tests/test_collections.pytest_applications_sorted sz(TestCollections.test_applications_sortedcCs<t}||t||dt||dtdS)NusergffA)rallrr owned_byZ newer_thanrrr r r!test_processes_typess z$TestCollections.test_processes_typescCs"td}|t|ddS)Nr)rr$r%Z assertGreaterlenr&r r r!test_processes_none_usersz(TestCollections.test_processes_none_userTz%@TODO Create Mock for Processes classcCsdtd}td}tgd|_t}||g||g||||d|||jdS)Ni)rrrr)rsetfilesr updateZassertInindex)rp1p2cr r r!test_processes_updates   z%TestCollections.test_processes_updatecCstd}td}td}tdd}td}t||||g}||||gdt||gd||d||||gdjdS)Nrrrr{rr)rr r intersectionrZassertIsNotNoneZmodified)rr.r/Zp3Zp4Zp5c1r r r!test_packages_intersection,s *z*TestCollections.test_packages_intersectioncCsxtddi}tddi}tddi}t|||g}dd|DhdksLJ|dddd d|Dhd kstJdS) NrrrrcSsh|] }|jqSr r.0ar r r! =z6TestCollections.test_replace_values..>rrrrcSsh|] }|jqSr r6r7r r r!r:?r;>rrr)rr Zreplace_values)rrrrr4r r r!test_replace_values7s   z#TestCollections.test_replace_valuescCsPt}|d}tt|dD](}||||dkr"tdq"dS)N create_timerz$The collection isn't sorted properly)rr$rranger(r= Exception)rr4Zc2ir r r!test_collection_sorted_callableAs  z/TestCollections.test_collection_sorted_callablecCsZtj}tdd|d}tdd|d}t||g}|d}|dd|DddgdS) za https://github.com/FrostyX/tracer/issues/151 https://github.com/FrostyX/tracer/issues/156 rNrrrrcSsg|] }|jqSr )r)r8Zappr r r! Sr;zGTestCollections.test_application_sorted_none_helper..)rrrr rr)rrrrrZcollection_sortedr r r!#test_application_sorted_none_helperIs  z3TestCollections.test_application_sorted_none_helperN) __name__ __module__ __qualname__r"r'r)unittestZskipIfr1r5r<rArCr r r r!r s     r N)Z__meta__Ztracer.resources.applicationsrrZtracer.resources.processesrrZtracer.resources.packagerZtracer.resources.collectionsr r r r rGZTestCaser r r r r!s  tests/__pycache__/test_dnf.cpython-39.opt-1.pyc000064400000004364151114232410015315 0ustar00a "e%@svddlTzddlmZddlmZWney6Yn0eedkoJedkdGdd d ej Z e d krre d S) )*)IPackageManager)DnfZfedoraZmageiaz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestDnfcCs t|_dS)N)rmanagerselfr 9/usr/lib/python3.9/site-packages/tracer/tests/test_dnf.pysetUp sz TestDnf.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz1TestDnf.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz+TestDnf.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestDnf.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz&TestDnf.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestDnf.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.dnfr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_dnf.cpython-39.pyc000064400000004364151114232410014356 0ustar00a "e%@svddlTzddlmZddlmZWney6Yn0eedkoJedkdGdd d ej Z e d krre d S) )*)IPackageManager)DnfZfedoraZmageiaz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestDnfcCs t|_dS)N)rmanagerselfr 9/usr/lib/python3.9/site-packages/tracer/tests/test_dnf.pysetUp sz TestDnf.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz1TestDnf.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz+TestDnf.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestDnf.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz&TestDnf.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestDnf.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.dnfr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_dpkg.cpython-39.opt-1.pyc000064400000004356151114232410015474 0ustar00a "e@snddlTzddlmZddlmZWney6Yn0eedkdGdddej Z e d krje d S) )*)IPackageManager)DpkgZdebianz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestDpkgcCs t|_dS)N)rmanagerselfr :/usr/lib/python3.9/site-packages/tracer/tests/test_dpkg.pysetUp szTestDpkg.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz2TestDpkg.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz,TestDpkg.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestDpkg.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz'TestDpkg.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestDpkg.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.dpkgr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_dpkg.cpython-39.pyc000064400000004356151114232410014535 0ustar00a "e@snddlTzddlmZddlmZWney6Yn0eedkdGdddej Z e d krje d S) )*)IPackageManager)DpkgZdebianz/Skipping tests because they are distro-specificc@s<eZdZddZddZddZddZd d Zd d Zd S)TestDpkgcCs t|_dS)N)rmanagerselfr :/usr/lib/python3.9/site-packages/tracer/tests/test_dpkg.pysetUp szTestDpkg.setUpcCs||jtddS)Nz9Every package manager should inherit from IPackageManager)ZassertIsInstancerrrr r r )test_implements_package_manager_interface sz2TestDpkg.test_implements_package_manager_interfacecCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz)packages_newer_than() is not implemented!)rZpackages_newer_thanNotImplementedErrorfail Exceptionrr r r #test_package_newer_than_implementedsz,TestDpkg.test_package_newer_than_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nz'load_package_info() is not implemented!)rZload_package_inforrrrr r r test_load_package_infoszTestDpkg.test_load_package_infocCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz$packages_files() is not implemented!)rZ package_filesrrrrr r r test_package_files_implementedsz'TestDpkg.test_package_files_implementedcCsBz|jdWn,ty,|dYnty<Yn0dS)Nrz!provided_by() is not implemented!)rZ provided_byrrrrr r r test_provided_byszTestDpkg.test_provided_byN) __name__ __module__ __qualname__r r rrrrr r r r rs r__main__N) Z__meta__Z&tracer.packageManagers.ipackageManagerrZtracer.packageManagers.dpkgr ImportErrorZunittestZskipIfZDISTROZTestCaserrmainr r r r s tests/__pycache__/test_hooks.cpython-39.opt-1.pyc000064400000003476151114232410015674 0ustar00a "e@sddlTddlmZmZdaedddZedd gd d Zed d dZedddZGddde j Z e dkre dS))*) HooksObservermatchNapp1cCsdadS)Ndummycalledr r ;/usr/lib/python3.9/site-packages/tracer/tests/test_hooks.py hook_dummysr app2app3cCsdadS)N dummy_listrr r r r hook_dummy_list srfoocCstddS)Nrr appendr r r r hook_dummy_append1srbarcCstddS)Nrrr r r r hook_dummy_append2src@s,eZdZddZddZddZddZd S) TestHookscCst|_dadS)N)robserverr selfr r r setUpszTestHooks.setUpcCsF|d|td|d|td|d|tddS)Nrrr rr)rZ assertEqualr rr r r test_hook"s      zTestHooks.test_hookcCs,ga|d|d|tddgdS)Nrr)r rZassertListEqualrr r r test_hooks_list,s  zTestHooks.test_hooks_listcCs|d|tdS)NZ undefined)rZ assertIsNoner rr r r test_undefined_hook3s zTestHooks.test_undefined_hookN)__name__ __module__ __qualname__rrrrr r r r rs r__main__)Z__meta__Z tracer.hooksrrr r rrrZunittestZTestCaserrmainr r r r s     tests/__pycache__/test_hooks.cpython-39.pyc000064400000003476151114232410014735 0ustar00a "e@sddlTddlmZmZdaedddZedd gd d Zed d dZedddZGddde j Z e dkre dS))*) HooksObservermatchNapp1cCsdadS)Ndummycalledr r ;/usr/lib/python3.9/site-packages/tracer/tests/test_hooks.py hook_dummysr app2app3cCsdadS)N dummy_listrr r r r hook_dummy_list srfoocCstddS)Nrr appendr r r r hook_dummy_append1srbarcCstddS)Nrrr r r r hook_dummy_append2src@s,eZdZddZddZddZddZd S) TestHookscCst|_dadS)N)robserverr selfr r r setUpszTestHooks.setUpcCsF|d|td|d|td|d|tddS)Nrrr rr)rZ assertEqualr rr r r test_hook"s      zTestHooks.test_hookcCs,ga|d|d|tddgdS)Nrr)r rZassertListEqualrr r r test_hooks_list,s  zTestHooks.test_hooks_listcCs|d|tdS)NZ undefined)rZ assertIsNoner rr r r test_undefined_hook3s zTestHooks.test_undefined_hookN)__name__ __module__ __qualname__rrrrr r r r rs r__main__)Z__meta__Z tracer.hooksrrr r rrrZunittestZTestCaserrmainr r r r s     tests/__pycache__/test_lang.cpython-39.opt-1.pyc000064400000001251151114232410015457 0ustar00a "e@sHddlTddlmmZddlZGdddejZedkrDe dS))*Nc@seZdZddZdS)TestLangcCs|ttddS)N_)Z assertTruehasattrlang)selfr :/usr/lib/python3.9/site-packages/tracer/tests/test_lang.py test_provide_underscore_functionsz)TestLang.test_provide_underscore_functionN)__name__ __module__ __qualname__r r r r r rsr__main__) Z__meta__Ztracer.resources.langZ resourcesrosZunittestZTestCaserr mainr r r r s tests/__pycache__/test_query.cpython-39.opt-1.pyc000064400000002544151114232410015711 0ustar00a "e>@sNddlTddlmZmZGdddejZGdddeZe dkrJe d S) )*)QueryLazyc@seZdZddZddZdS) TestQuerycCsttd|_dS)N)Ztracer)r TracerMockquery)selfr ;/usr/lib/python3.9/site-packages/tracer/tests/test_query.pysetUpszTestQuery.setUpcCsB|j}||t|t|d|t|gddS)NgetABC) rZaffected_applicationsZassertIsInstancerZ assertTruehasattrZassertListEquallistr )r Z apps_queryr r r test_affected_applications s  z$TestQuery.test_affected_applicationsN)__name__ __module__ __qualname__r rr r r r rsrc@seZdZddZdddZdS)rcGsdS)Nr )r argsr r r __init__szTracerMock.__init__NcCsgdS)Nrr )r userr r r trace_affectedszTracerMock.trace_affected)N)rrrrrr r r r rsr__main__N) Z__meta__Z tracer.queryrrZunittestZTestCaserobjectrrmainr r r r s   tests/__init__.py000064400000000000151114232410007777 0ustar00tests/__meta__.py000064400000000446151114232410010000 0ustar00# Enable importing modules from parent directory (tracer's root directory) import os parentdir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) os.sys.path.insert(0, parentdir) import sys import unittest from tracer.resources.system import System DISTRO = System.distribution() tests/test_FilenameCleaner.py000064400000001656151114232410012333 0ustar00from unittest import TestCase from tracer.resources.FilenameCleaner import FilenameCleaner class TestFilenameCleaner(TestCase): def setUp(self): self.cleaner = FilenameCleaner() def test_strip(self): self.assertEqual("/lib/libdl.so", self.cleaner.strip("/lib/libdl-2.19.so")) self.assertEqual("/lib/libncurses.so", self.cleaner.strip("/lib/libncurses.so.5.9")) self.assertEqual("/bin/bash", self.cleaner.strip("/bin/bash")) self.assertEqual("/usr/share/wicd/curses/wicd-curses.py", self.cleaner.strip("/usr/share/wicd/curses/wicd-curses.py")) self.assertEqual("/usr/bin/gvim", self.cleaner.strip("/usr/bin/gvim#new (deleted)")) self.assertEqual("/usr/lib64/kde4/kded_networkmanagement.so", self.cleaner.strip("/usr/lib64/kde4/kded_networkmanagement.so;53c7cd86") ) self.assertEqual("/usr/lib64/firefox/plugin-container", self.cleaner.strip("/usr/lib64/firefox/plugin-container.#prelink#.N3n7Rk (deleted)") ) tests/test_alpm.py000064400000002446151114232410010250 0ustar00from .__meta__ import * try: from tracer.packageManagers.ipackageManager import IPackageManager from tracer.packageManagers.alpm import Alpm except ImportError: pass @unittest.skipIf((DISTRO != "arch" and DISTRO != "archarm"), "Skipping tests because they are distro-specific") class TestAlpm(unittest.TestCase): def setUp(self): self.manager = Alpm() def test_implements_package_manager_interface(self): self.assertIsInstance(self.manager, IPackageManager, "Every package manager should inherit from IPackageManager") def test_package_newer_than_implemented(self): try: self.manager.packages_newer_than(0) except NotImplementedError: self.fail("packages_newer_than() is not implemented!") except Exception: pass def test_load_package_info(self): try: self.manager.load_package_info("") except NotImplementedError: self.fail("load_package_info() is not implemented!") except Exception: pass def test_package_files_implemented(self): try: self.manager.package_files("") except NotImplementedError: self.fail("packages_files() is not implemented!") except Exception: pass def test_provided_by(self): try: self.manager.provided_by("") except NotImplementedError: self.fail("provided_by() is not implemented!") except Exception: pass if __name__ == '__main__': unittest.main() tests/test_applications.py000064400000007646151114232410012014 0ustar00from .__meta__ import * from tracer.paths import DATA_DIR from tracer.resources.applications import Applications, Application from tracer.resources.collections import ApplicationsCollection, ProcessesCollection try: from unittest.mock import patch, mock_open builtins_open = "builtins.open" except: from mock import patch, mock_open builtins_open = "__builtin__.open" class TestApplications(unittest.TestCase): @classmethod def setUpClass(cls): cls.DEFINITIONS = [x for x in Applications.DEFINITIONS if x.startswith(DATA_DIR)] def setUp(self): Applications.DEFINITIONS = self.DEFINITIONS Applications._apps = None def test_apps_types(self): self.assertIsInstance(Applications.all(), ApplicationsCollection) def test_application_processes(self): application = Applications.all()[0] self.assertIsInstance(application.instances, ProcessesCollection) def test_apps_attributes(self): i = 1 for a in Applications.all(): if ("name" not in a) or len(a) <= 1: self.fail("Missing name in definition #" + str(i)) if "type" in a and a.type not in Applications.TYPES.values(): self.fail("Unknown type in application: " + a.type) n = 6 if "rename" in a else 5 self.assertEqual(len(a), n, "Application {0} has unsupported attribute".format(a.name)) i += 1 def test_apps_duplicity(self): apps = Applications.all() for a in apps: if self._count(a.name, apps) > 1: self.fail("Duplicate definitions for: " + a.name) @patch('tracer.resources.applications.System.init_system', return_value="dummy") def test_app_with_no_definition(self, init_system): app_name = "NON_EXISTING_APPLICATION" app = Applications.find(app_name) self.assertEqual(app.name, app_name) self.assertEqual(app.type, Applications.DEFAULT_TYPE) self.assertEqual(app.helper, None) self.assertEqual(app.note, None) self.assertEqual(len(app), 5, "Application {0} has unsupported attribute".format(app.name)) def test_representations(self): rule = Application({"name": "foo"}) self.assertEqual(str(rule), "") self.assertEqual(repr(rule), "") def test_contains_name(self): a1 = Application({"name": "foo", "type": "applicaiton", "helper": "some helper"}) a2 = Application({"name": "foo", "type": "application", "helper": "some helper with {NAME} argument"}) self.assertFalse(a1.helper_contains_name) self.assertTrue(a2.helper_contains_name) def test_contains_formating(self): a1 = Application({"name": "foo", "type": "applicaiton", "helper": "some helper"}) a3 = Application({"name": "foo", "type": "application", "helper": "some helper with {FOO} argument"}) self.assertFalse(a1.helper_contains_formating) self.assertTrue(a3.helper_contains_formating) def test_helper_contains_when_none(self): a1 = Application({"name": "foo", "type": "applicaiton", "helper": None}) self.assertFalse(a1.helper_contains_formating) self.assertFalse(a1.helper_contains_name) @patch("tracer.resources.system.System.init_system", return_value="systemd") def test_load(self, _init_system): """ Test parsing a single XML file with applications """ Applications.DEFINITIONS = ["whatever-file.xml"] data = ( "" " " " " " " " " " " "" ) with patch(builtins_open, mock_open(read_data=data)): apps = Applications.all() self.assertEqual(len(apps), 3) self.assertTrue(all([isinstance(x, Application) for x in apps])) self.assertEqual(apps[0].name, "foo") self.assertTrue(apps[0].helper.endswith("systemctl restart foo")) self.assertEqual(apps[2].type, "session") self.assertIn("kill it", apps[2].helper) def _count(self, app_name, apps): count = 0 for a in apps: if a.name == app_name: count += 1 return count if __name__ == '__main__': unittest.main() tests/test_collections.py000064400000006241151114232410011632 0ustar00from .__meta__ import * from tracer.resources.applications import Applications, Application from tracer.resources.processes import Processes, AffectedProcess from tracer.resources.package import Package from tracer.resources.collections import ApplicationsCollection, ProcessesCollection, PackagesCollection, AffectedProcessesCollection class TestCollections(unittest.TestCase): def test_applications_sorted(self): default_type = Applications.DEFAULT_TYPE a1 = Application({'name': 'foo', 'helper': 'bar', 'type': default_type}) a2 = Application({'name': 'baz', 'helper': 'qux', 'type': default_type}) a3 = Application({'name': 'quux', 'helper': 'corge', 'type': default_type}) collection = ApplicationsCollection([a1, a2, a3]) self.assertEqual(collection.sorted('name'), ApplicationsCollection([a2, a1, a3])) self.assertEqual(collection.sorted('helper'), ApplicationsCollection([a1, a3, a2])) self.assertIsInstance(collection, ApplicationsCollection) def test_processes_types(self): collection = Processes.all() self.assertIsInstance(collection, ProcessesCollection) self.assertIsInstance(collection.owned_by('user'), ProcessesCollection) self.assertIsInstance(collection.newer_than(1414006430.1), ProcessesCollection) def test_processes_none_user(self): collection = Processes.all().owned_by(None) self.assertGreater(len(collection), 0) @unittest.skipIf(True, "@TODO Create Mock for Processes class") def test_processes_update(self): p1 = AffectedProcess(1234) p2 = AffectedProcess(1234) p2.files = set(['foo', 'bar', 'baz']) c = AffectedProcessesCollection() c.update([p1]) c.update([p2]) self.assertIn(p1, c) self.assertIn('bar', c[c.index(p1)].files) def test_packages_intersection(self): p1 = Package("foo") p2 = Package("bar") p3 = Package("baz") p4 = Package("qux", 123) p5 = Package("qux") c1 = PackagesCollection([p1, p2, p3, p4]) self.assertEqual(c1.intersection([p1, p3]).sorted("name"), PackagesCollection([p1, p3]).sorted("name")) self.assertEqual(c1.intersection(None), c1) self.assertIsNotNone(c1.intersection([p5])[0].modified) def test_replace_values(self): a1 = Application({"name": "foo"}) a2 = Application({"name": "bar"}) a3 = Application({"name": "baz"}) c1 = ApplicationsCollection([a1, a2, a3]) assert {a.name for a in c1} == {"foo", "bar", "baz"} c1.replace_values("name", "foo", "qux") assert {a.name for a in c1} == {"qux", "bar", "baz"} def test_collection_sorted_callable(self): c1 = Processes.all() c2 = c1.sorted("create_time") for i in range(len(c2) - 1): if c2[i].create_time() > c2[i+1].create_time(): raise Exception("The collection isn't sorted properly") def test_application_sorted_none_helper(self): """ https://github.com/FrostyX/tracer/issues/151 https://github.com/FrostyX/tracer/issues/156 """ default_type = Applications.DEFAULT_TYPE a1 = Application({'name': 'foo', 'helper': None, 'type': default_type}) a2 = Application({'name': 'baz', 'helper': 'qux', 'type': default_type}) collection = ApplicationsCollection([a1, a2]) collection_sorted = collection.sorted('helper') self.assertEqual([app.helper for app in collection_sorted], ["qux", None]) tests/test_dnf.py000064400000002445151114232410010065 0ustar00from .__meta__ import * try: from tracer.packageManagers.ipackageManager import IPackageManager from tracer.packageManagers.dnf import Dnf except ImportError: pass @unittest.skipIf((DISTRO != 'fedora') and (DISTRO != 'mageia'), "Skipping tests because they are distro-specific") class TestDnf(unittest.TestCase): def setUp(self): self.manager = Dnf() def test_implements_package_manager_interface(self): self.assertIsInstance(self.manager, IPackageManager, "Every package manager should inherit from IPackageManager") def test_package_newer_than_implemented(self): try: self.manager.packages_newer_than(0) except NotImplementedError: self.fail("packages_newer_than() is not implemented!") except Exception: pass def test_load_package_info(self): try: self.manager.load_package_info("") except NotImplementedError: self.fail("load_package_info() is not implemented!") except Exception: pass def test_package_files_implemented(self): try: self.manager.package_files("") except NotImplementedError: self.fail("packages_files() is not implemented!") except Exception: pass def test_provided_by(self): try: self.manager.provided_by("") except NotImplementedError: self.fail("provided_by() is not implemented!") except Exception: pass if __name__ == '__main__': unittest.main() tests/test_dpkg.py000064400000002416151114232410010241 0ustar00from .__meta__ import * try: from tracer.packageManagers.ipackageManager import IPackageManager from tracer.packageManagers.dpkg import Dpkg except ImportError: pass @unittest.skipIf(DISTRO != 'debian', "Skipping tests because they are distro-specific") class TestDpkg(unittest.TestCase): def setUp(self): self.manager = Dpkg() def test_implements_package_manager_interface(self): self.assertIsInstance(self.manager, IPackageManager, "Every package manager should inherit from IPackageManager") def test_package_newer_than_implemented(self): try: self.manager.packages_newer_than(0) except NotImplementedError: self.fail("packages_newer_than() is not implemented!") except Exception: pass def test_load_package_info(self): try: self.manager.load_package_info("") except NotImplementedError: self.fail("load_package_info() is not implemented!") except Exception: pass def test_package_files_implemented(self): try: self.manager.package_files("") except NotImplementedError: self.fail("packages_files() is not implemented!") except Exception: pass def test_provided_by(self): try: self.manager.provided_by("") except NotImplementedError: self.fail("provided_by() is not implemented!") except Exception: pass if __name__ == '__main__': unittest.main() tests/test_hooks.py000064400000002016151114232410010433 0ustar00from .__meta__ import * from tracer.hooks import HooksObserver, match called = None @match("app1") def hook_dummy(): global called called = "dummy" @match(["app2", "app3"]) def hook_dummy_list(): global called called = "dummy_list" @match("foo") def hook_dummy_append1(): global called called.append("foo") @match("bar") def hook_dummy_append2(): global called called.append("bar") class TestHooks(unittest.TestCase): def setUp(self): self.observer = HooksObserver() global called called = None def test_hook(self): self.observer("app1") self.assertEqual(called, "dummy") self.observer("app2") self.assertEqual(called, "dummy_list") self.observer("app3") self.assertEqual(called, "dummy_list") def test_hooks_list(self): global called called = [] self.observer("foo") self.observer("bar") self.assertListEqual(called, ["foo", "bar"]) def test_undefined_hook(self): global called self.observer("undefined") self.assertIsNone(called) if __name__ == '__main__': unittest.main() tests/test_lang.py000064400000000356151114232410010236 0ustar00from .__meta__ import * import tracer.resources.lang as lang import os class TestLang(unittest.TestCase): def test_provide_underscore_function(self): self.assertTrue(hasattr(lang, '_')) if __name__ == '__main__': unittest.main() tests/test_package.py000064400000000563151114232410010710 0ustar00from .__meta__ import * from tracer.resources.package import Package class TestPackage(unittest.TestCase): def test_equality(self): p1 = Package("foo") p2 = Package("foo") p3 = Package("bar") self.assertEqual(p1, p2) self.assertNotEqual(p1, p3) def test_representation(self): package = Package("foo") self.assertEqual(repr(package), "") tests/test_portage.py000064400000002432151114232410010753 0ustar00from .__meta__ import * try: from tracer.packageManagers.ipackageManager import IPackageManager from tracer.packageManagers.portage import Portage except ImportError: pass @unittest.skipIf(DISTRO != 'gentoo', "Skipping tests because they are distro-specific") class TestPortage(unittest.TestCase): def setUp(self): self.manager = Portage() def test_implements_package_manager_interface(self): self.assertIsInstance(self.manager, IPackageManager, "Every package manager should inherit from IPackageManager") def test_package_newer_than_implemented(self): try: self.manager.packages_newer_than(0) except NotImplementedError: self.fail("packages_newer_than() is not implemented!") except Exception: pass def test_load_package_info(self): try: self.manager.load_package_info("") except NotImplementedError: self.fail("load_package_info() is not implemented!") except Exception: pass def test_package_files_implemented(self): try: self.manager.package_files("") except NotImplementedError: self.fail("packages_files() is not implemented!") except Exception: pass def test_provided_by(self): try: self.manager.provided_by("") except NotImplementedError: self.fail("provided_by() is not implemented!") except Exception: pass if __name__ == '__main__': unittest.main() tests/test_processes.py000064400000004611151114232410011321 0ustar00from .__meta__ import * from tracer.resources.processes import Processes, Process, ProcessWrapper from tracer.resources.SystemdDbus import SystemdDbus from tracer.resources.collections import ProcessesCollection import os import subprocess class TestProcesses(unittest.TestCase): @unittest.skipIf(True, "@TODO Create Mock for Processes class") def test_children(self): process = Processes.all()[0] children = process.children() self.assertIsInstance(children, ProcessesCollection) for child in children: self.assertIsInstance(child, Process) @unittest.skipIf(True, "@TODO Create Mock for Processes class") def test_unique_process(self): process = Process(os.getpid()) parent = Process(os.getppid()) self.assertIs(process, Process(os.getpid())) self.assertIs(parent, process.parent()) self.assertIn(process, parent.children()) Process.reset_cache() process2 = Process(os.getpid()) self.assertEqual(process, process2) self.assertIsNot(process, process2) @unittest.skipIf(True, "@TODO Create Mock for Processes class") def test_process_caching(self): process = Process(os.getpid()) # Populate the cache entry for children process.children() child = subprocess.Popen(os.sys.executable, stdin=subprocess.PIPE) self.assertEqual(0, len(process.children())) process.rebuild_cache() self.assertEqual(1, len(process.children())) child.terminate() def test_name_sshd(self): p1 = ProcessMock() p1.data = {"name": "sshd", "exe": "/usr/sbin/sshd", "cmdline": ["/usr/sbin/sshd", "-D", "foo", "bar"]} assert p1.name() == "sshd" p2 = ProcessMock() p2.data = {"name": "sshd", "exe": "/usr/sbin/sshd", "cmdline": ["some", "thing", "and", "arguments", "idk", "what"]} assert p2.name() == "ssh-thing-session" # I don't know what case this is in a real life but see #129 and #125 p3 = ProcessMock() p3.data = {"name": "sshd", "exe": "/usr/sbin/sshd", "cmdline": ["withoutparams"]} assert p3.name() == "sshd" @unittest.skipIf(True, "@TODO Create Mock for Processes class") def test_dbus(self): dbus = SystemdDbus() pids = Processes.pids() nonexisting = max(pids) + 999 assert dbus.has_service_property_from_pid(1, "PAMName") is False assert dbus.has_service_property_from_pid(nonexisting, "PAMName") is False class ProcessMock(ProcessWrapper): def __init__(self): self.data = {} def _attr(self, name): return self.data[name] tests/test_query.py000064400000001076151114232410010462 0ustar00from .__meta__ import * from tracer.query import Query, Lazy class TestQuery(unittest.TestCase): def setUp(self): self.query = Query(tracer=TracerMock) def test_affected_applications(self): apps_query = self.query.affected_applications() self.assertIsInstance(apps_query, Lazy) self.assertTrue(hasattr(apps_query, "get")) self.assertListEqual(list(apps_query.get()), ["A", "B", "C"]) class TracerMock(object): def __init__(self, *args): pass def trace_affected(self, user=None): return ["A", "B", "C"] if __name__ == '__main__': unittest.main() tests/test_rules.py000064400000004302151114232410010442 0ustar00from .__meta__ import * from tracer.paths import DATA_DIR from tracer.resources.rules import Rules, Rule try: from unittest.mock import patch, mock_open builtins_open = "builtins.open" except: from mock import patch, mock_open builtins_open = "__builtin__.open" class TestRules(unittest.TestCase): @classmethod def setUpClass(cls): cls.DEFINITIONS = [x for x in Rules.DEFINITIONS if x.startswith(DATA_DIR)] def setUp(self): Rules.DEFINITIONS = self.DEFINITIONS Rules._rules = None def test_rules_types(self): for rule in Rules.all(): self.assertIsInstance(rule, Rule) def test_rules_attributes(self): i = 1 for r in Rules.all(): if ("name" not in r) or ("action" not in r): self.fail("Missing attributes in rule #" + str(i)) if r.action not in Rules.ACTIONS.values(): self.fail("Unknown action in rule: " + r.name) if len(r) > 2: self.fail("Unsupported attributes in rule: " + r.name) i += 1 def test_rules_duplicity(self): rules = Rules.all() for r in rules: if rules.count(r) > 1: self.fail("Duplicate rules for: " + r.name) def test_app_with_no_rule(self): self.assertIsNone(Rules.find("NON_EXISTING_APPLICATION")) def test_representations(self): rule = Rule({"name": "foo"}) self.assertEqual(str(rule), "") self.assertEqual(repr(rule), "") def test_update(self): r1 = Rule({"name": "foo", "action": "bar"}) r2 = Rule({"name": "foo", "action": "baz"}) r1.update(r2) self.assertEqual(r1.action, "baz") def test_load(self): """ Test parsing a single XML file with rules """ Rules.DEFINITIONS = ["whatever-file.xml"] data = ( "" " " " " "" ) with patch(builtins_open, mock_open(read_data=data)): rules = Rules.all() self.assertEqual(len(rules), 2) self.assertTrue(all([isinstance(x, Rule) for x in rules])) self.assertEqual(rules[0].name, "foo") self.assertEqual(rules[0].action, "return") self.assertEqual(rules[1].name, "bar") def _count(self, app_name, apps): count = 0 for a in apps: if a.name == app_name: count += 1 return count if __name__ == '__main__': unittest.main() tests/test_tracer.py000064400000006633151114232410010601 0ustar00from .__meta__ import * from tracer.resources.tracer import Tracer from tracer.resources.rules import Rules from tracer.resources.applications import Applications, Application from tracer.resources.processes import AffectedProcess from tracer.resources.collections import \ ProcessesCollection, \ PackagesCollection, \ ApplicationsCollection, \ AffectedProcessesCollection try: from unittest.mock import patch except: from mock import patch class TestRules(unittest.TestCase): def setUp(self): Applications._apps = ApplicationsCollection() self.tracer = Tracer(PackageManagerMock(), Rules, Applications, memory=dump_memory_mock) self.tracer.timestamp = 5555 # Sure, it should be a UNIX timestamp value Applications._append_application({"name": "kernel", "ignore": True}) Application.processes_factory = ProcessesMock @patch('tracer.resources.applications.System.init_system', return_value="dummy") def test_trace_affected(self, init_system): affected = self.tracer.trace_affected() self.assertSetEqual(set(affected), set([Applications.find("baz"), Applications.find("qux")])) self.assertIsInstance(affected, ApplicationsCollection) def test_trace_application(self): affected = self.tracer.trace_application(Applications.find("baz"), AffectedProcessMock) self.assertIsInstance(affected, AffectedProcessesCollection) self.assertEqual(len(affected), 1) process = affected[0] self.assertIsInstance(process, AffectedProcess) self.assertEqual(process.pid, 4) # pid of "baz" in our mock class ProcessMock(object): def __init__(self, pid, name, create_time, files): self.pid = pid self.files = files self._name = name self._create_time = create_time def name(self): return self._name @property def real_name(self): return self._name @property def is_interpreted(self): return False @property def is_session(self): return False def create_time(self): return self._create_time def children(self): return [] def parent(self): return None class AffectedProcessMock(AffectedProcess): def __init__(self, pid=None): # Do not run the parent __init__ self.pid = pid self.packages = set() self.files = set() class ProcessesMock(object): @staticmethod def all(): return ProcessesCollection([ ProcessMock(2, "foo", 1111, ["file1", "file2", "file3"]), ProcessMock(3, "bar", 9999, ["file10", "file11", "file12"]), ProcessMock(4, "baz", 6666, ["file7", "file1", "file3"]), ProcessMock(5, "qux", 7777, ["file4", "file9"]), ]) class PackageMock(object): def __init__(self, name, modified, files): self.name = name self.modified = modified self.files = files class PackageManagerMock(object): _packages = [ PackageMock("A", 3333, ["file1", "file2", "file3"]), PackageMock("B", 4444, ["file4", "file5", "file6"]), PackageMock("C", 7777, ["file7", "file8", "file9"]), PackageMock("D", 8888, ["file10", "file11", "file12"]), ] def packages_newer_than(self, unix_time): return PackagesCollection(filter(lambda p: p.modified >= unix_time, self._packages)) def package_files(self, pkg_name): for package in self._packages: if package.name == pkg_name: return package.files def dump_memory_mock(user=None): memory = {} for process in ProcessesMock.all(): for file in process.files: if file in memory: memory[file].append(process) else: memory[file] = [process] return memory if __name__ == '__main__': unittest.main() tests/test_views.py000064400000023500151114232410010446 0ustar00from __future__ import unicode_literals from .__meta__ import * from tracer.resources.pycomp import StringIO from tracer.views.default import DefaultView from tracer.views.helper import HelperView from tracer.resources.applications import Applications, Application from tracer.resources.collections import ApplicationsCollection from tracer.resources.package import Package from .test_tracer import ProcessMock, AffectedProcessMock import tracer.views.default import tracer.views.helper import tracer.views.note_for_hidden import gettext t = gettext.translation('tracer', fallback=True, languages=["en"]) _ = t.ugettext try: from unittest.mock import patch except: from mock import patch # Mock the gettext function to use only english tracer.views.default._ = _ tracer.views.helper._ = _ tracer.views.note_for_hidden._ = _ class TestViews(unittest.TestCase): def setUp(self): self.out = StringIO() def test_default_none(self): view = DefaultView(self.out) view.assign("args", ArgsMock()) view.assign("applications", ApplicationsCollection([])) view.render() self.assertEqual(self.out.getvalue(), "") def test_default_with_helpers(self): view = DefaultView(self.out) view.assign("args", ArgsMock()) view.assign("applications", ApplicationsCollection([ Application({"type": "application", "helper": "first helper", "name": "first"}), Application({"type": "application", "helper": "second helper", "name": "second"}), Application({"type": "application", "helper": "third helper", "name": "third"}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * Some applications using:\n" " first helper\n" " second helper\n" " third helper\n" )) def test_default_without_helpers(self): view = DefaultView(self.out) view.assign("args", ArgsMock()) view.assign("applications", ApplicationsCollection([ Application({"type": "application", "name": "foo", "helper": None}), Application({"type": "application", "name": "bar", "helper": None}), Application({"type": "application", "name": "baz", "helper": None}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * These applications manually:\n" " bar\n" " baz\n" " foo\n" )) def test_default_with_without_helpers(self): view = DefaultView(self.out) view.assign("args", ArgsMock()) view.assign("applications", ApplicationsCollection([ Application({"type": "application", "helper": "first helper", "name": "first"}), Application({"type": "application", "helper": "second helper", "name": "second"}), Application({"type": "application", "helper": "third helper", "name": "third"}), Application({"type": "application", "name": "foo", "helper": None}), Application({"type": "application", "name": "bar", "helper": None}), Application({"type": "application", "name": "baz", "helper": None}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * Some applications using:\n" " first helper\n" " second helper\n" " third helper\n" "\n" " * These applications manually:\n" " bar\n" " baz\n" " foo\n" )) def test_default_all_session(self): view = DefaultView(self.out) view.assign("args", ArgsMock(all=True)) view.assign("applications", ApplicationsCollection([ Application({"type": "session", "name": "foo", "helper": "h1"}), Application({"type": "session", "name": "bar", "helper": "h2"}), Application({"type": "session", "name": "baz", "helper": "h3"}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * These applications restarting your session:\n" " bar\n" " baz\n" " foo\n" )) def test_default_all_static(self): view = DefaultView(self.out) view.assign("args", ArgsMock(all=True)) view.assign("applications", ApplicationsCollection([ Application({"type": "static", "name": "foo", "helper": "h1"}), Application({"type": "static", "name": "bar", "helper": "h2"}), Application({"type": "static", "name": "baz", "helper": "h3"}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * These applications rebooting your computer:\n" " bar\n" " baz\n" " foo\n" )) def test_default_all_session_static(self): view = DefaultView(self.out) view.assign("args", ArgsMock(all=True)) view.assign("applications", ApplicationsCollection([ Application({"type": "session", "name": "foo", "helper": "h1"}), Application({"type": "session", "name": "bar", "helper": "h2"}), Application({"type": "session", "name": "baz", "helper": "h3"}), Application({"type": "static", "name": "aaa", "helper": "h4"}), Application({"type": "static", "name": "bbb", "helper": "h5"}), Application({"type": "static", "name": "ccc", "helper": "h6"}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * These applications restarting your session:\n" " bar\n" " baz\n" " foo\n" "\n" " * These applications rebooting your computer:\n" " aaa\n" " bbb\n" " ccc\n" )) def test_default_all(self): view = DefaultView(self.out) view.assign("args", ArgsMock(all=True)) view.assign("applications", ApplicationsCollection([ Application({"type": "application", "helper": "first helper", "name": "first"}), Application({"type": "application", "helper": "second helper", "name": "second"}), Application({"type": "application", "name": "foo", "helper": None}), Application({"type": "application", "name": "bar", "helper": None}), Application({"type": "session", "name": "baz", "helper": "h1"}), Application({"type": "session", "name": "qux", "helper": "h2"}), Application({"type": "static", "name": "aaa", "helper": "h3"}), Application({"type": "static", "name": "bbb", "helper": "h4"}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * Some applications using:\n" " first helper\n" " second helper\n" "\n" " * These applications manually:\n" " bar\n" " foo\n" "\n" " * These applications restarting your session:\n" " baz\n" " qux\n" "\n" " * These applications rebooting your computer:\n" " aaa\n" " bbb\n" )) def test_default_not_all(self): view = DefaultView(self.out) view.assign("args", ArgsMock()) view.assign("applications", ApplicationsCollection([ Application({"type": "application", "helper": "first helper", "name": "first"}), Application({"type": "application", "helper": "second helper", "name": "second"}), Application({"type": "application", "name": "foo", "helper": None}), Application({"type": "application", "name": "bar", "helper": None}), Application({"type": "session", "name": "baz", "helper": "h1"}), Application({"type": "session", "name": "qux", "helper": "h2"}), Application({"type": "static", "name": "aaa", "helper": "h3"}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "You should restart:\n" " * Some applications using:\n" " first helper\n" " second helper\n" "\n" " * These applications manually:\n" " bar\n" " foo\n" "\n" "Additionally, there are:\n" " - 2 processes requiring restart of your session (i.e. Logging out & Logging in again)\n" " - 1 processes requiring reboot\n" )) def test_default_note_only(self): view = DefaultView(self.out) view.assign("args", ArgsMock()) view.assign("applications", ApplicationsCollection([ Application({"type": "session", "name": "foo", "helper": "h1"}), Application({"type": "session", "name": "bar", "helper": "h2"}), Application({"type": "static", "name": "baz", "helper": "h3"}), ])) view.render() self.assertEqual(self.out.getvalue(), ( "There are:\n" " - 2 processes requiring restart of your session (i.e. Logging out & Logging in again)\n" " - 1 processes requiring reboot\n" )) @patch('tracer.resources.applications.System.init_system', return_value="dummy") def test_helper(self, init_system): processes = [ ProcessMock(2, "foo", 1234, ["file1", "file2"]), ProcessMock(3, "foo", 5678, ["file2", "file3"]), ] package = Package("foopackage") package.modified = None package.description = "Foo package description" package.category = "categ" package.files = ["file1", "file2"] a1 = AffectedProcessMock(2) a1.packages = set([package]) affected_by = [a1] view = HelperView(self.out) view.assign("args", ArgsMock(verbose=2)) view.assign("processes", processes) view.assign("application", Applications.find("foo")) view.assign("package", package) view.assign("affected_by", affected_by) view.assign("affects", None) view.render() self.assertEqual(self.out.getvalue(), ( "* foo\n" " Package: foopackage\n" " Description: Foo package description\n" " Type: Application\n" " State: foo has been started by None some-time ago. PID - 2\n" " foo has been started by None some-time ago. PID - 3\n" "\n" " Affected by:\n" " foopackage\n" " file1\n" " file2\n" )) class ArgsMock(object): all = quiet = None def __init__(self, all=False, quiet=False, user=False, verbose=False): self.all = all self.quiet = quiet self.user = user self.verbose = verbose class ProcessMock(object): def __init__(self, pid, name, create_time, files): self.parent = None self.pid = pid self.files = files self._name = name self._create_time = create_time self.str_started_ago = "some-time" def name(self): return self._name def create_time(self): return self._create_time def children(self): return [] def username(self): return None tests/test_yum.py000064400000002412151114232410010122 0ustar00from .__meta__ import * try: from tracer.packageManagers.ipackageManager import IPackageManager from tracer.packageManagers.yum import Yum except ImportError: pass @unittest.skipIf(DISTRO != 'fedora', "Skipping tests because they are distro-specific") class TestYum(unittest.TestCase): def setUp(self): self.manager = Yum() def test_implements_package_manager_interface(self): self.assertIsInstance(self.manager, IPackageManager, "Every package manager should inherit from IPackageManager") def test_package_newer_than_implemented(self): try: self.manager.packages_newer_than(0) except NotImplementedError: self.fail("packages_newer_than() is not implemented!") except Exception: pass def test_load_package_info(self): try: self.manager.load_package_info("") except NotImplementedError: self.fail("load_package_info() is not implemented!") except Exception: pass def test_package_files_implemented(self): try: self.manager.package_files("") except NotImplementedError: self.fail("packages_files() is not implemented!") except Exception: pass def test_provided_by(self): try: self.manager.provided_by("") except NotImplementedError: self.fail("provided_by() is not implemented!") except Exception: pass if __name__ == '__main__': unittest.main() views/__pycache__/__init__.cpython-39.opt-1.pyc000064400000002336151114232410015236 0ustar00a "e@sLddlmZddlmZddlmZmZGdddeZGdddeZdS) )print_function)unicode_literals) __stdout__ version_infoc@s eZdZdS) ArgumentsN)__name__ __module__ __qualname__r r 9/usr/lib/python3.9/site-packages/tracer/views/__init__.pyrsrc@s<eZdZeZdZefddZddZddZ d dd Z dS) ViewNcCs ||_dSN)out)selfrr r r __init__sz View.__init__cCs||jj|<dSr args__dict__)rkeyvaluer r r assignsz View.assigncCs |jj|Sr r)rrr r r getszView.getcCs(tjdkr|d}t|||jddS)Nutf8)endfile)rmajorencodeprintr)rtextrr r r rs  z View.print)N) rrr rrrrrrrrr r r r r s  r N) Z __future__rrsysrrobjectrr r r r r s  views/__pycache__/__init__.cpython-39.pyc000064400000002336151114232410014277 0ustar00a "e@sLddlmZddlmZddlmZmZGdddeZGdddeZdS) )print_function)unicode_literals) __stdout__ version_infoc@s eZdZdS) ArgumentsN)__name__ __module__ __qualname__r r 9/usr/lib/python3.9/site-packages/tracer/views/__init__.pyrsrc@s<eZdZeZdZefddZddZddZ d dd Z dS) ViewNcCs ||_dSN)out)selfrr r r __init__sz View.__init__cCs||jj|<dSr args__dict__)rkeyvaluer r r assignsz View.assigncCs |jj|Sr r)rrr r r getszView.getcCs(tjdkr|d}t|||jddS)Nutf8)endfile)rmajorencodeprintr)rtextrr r r rs  z View.print)N) rrr rrrrrrrrr r r r r s  r N) Z __future__rrsysrrobjectrr r r r r s  views/__pycache__/blocks.cpython-39.opt-1.pyc000064400000002577151114232410014763 0ustar00a "e @s@ddlmZddlmZddlmZddlZGdddeZdS))print_function)unicode_literals)ViewNc@s(eZdZdZddZddZddZdS) BlocksViewzh Assign ``blocks`` with this list [ { "title": "...", "content": "some text", }, ... ] cCs^t|jjD]L\}}|dr d|vr2||d|j|ddd||r |dq dS)Ncontenttitle)end) enumerateargsblocksprintnextselfindexblockr7/usr/lib/python3.9/site-packages/tracer/views/blocks.pyrenders zBlocksView.rendercCs,|jj|ddD]}|drdSqdS)zs   views/__pycache__/blocks.cpython-39.pyc000064400000002577151114232410014024 0ustar00a "e @s@ddlmZddlmZddlmZddlZGdddeZdS))print_function)unicode_literals)ViewNc@s(eZdZdZddZddZddZdS) BlocksViewzh Assign ``blocks`` with this list [ { "title": "...", "content": "some text", }, ... ] cCs^t|jjD]L\}}|dr d|vr2||d|j|ddd||r |dq dS)Ncontenttitle)end) enumerateargsblocksprintnextselfindexblockr7/usr/lib/python3.9/site-packages/tracer/views/blocks.pyrenders zBlocksView.rendercCs,|jj|ddD]}|drdSqdS)zs   views/__pycache__/default.cpython-39.opt-1.pyc000064400000006556151114232410015133 0ustar00a "ed @sddlmZddlmZddlmZddlmZddlmZddl m Z ddl m Z dd l mZdd lmZdd lZGd d d eZd S))print_function)unicode_literals)View)_) Applications)NoteForHiddenView) BlocksView)StringIO) version_infoNc@seZdZddZdS) DefaultViewcsfdd}fdd}fdd}fdd}fd d }d td |d d td|d d td|d g}jjjr|d td|tjdd |d td|tjdd n|d|itj}|d|| r td| dS)Ncsd}tjdtjdtjdg}jj|d}|D]<}d|j }|j rl|j sl|d |j 7}|d|d 7}q@|S) NSESSIONSTATICERASEDhelperz; z # {}  )rTYPESargs applications with_helpers exclude_typesuniquesortedjoinhelpersZhelper_contains_formatingZhelper_contains_nameformatname)contenttypesr applicationrself8/usr/lib/python3.9/site-packages/tracer/views/default.pywith_helpers_contents   z0DefaultView.render..with_helpers_contentcsFd}jjtjdd}|D]}|d|jd7}q*|SNr rrrr) rrrrrrZwithout_helpersrrrZappsr!r"r$r%without_helpers_content s z3DefaultView.render..without_helpers_contentcsDd}jjtjdgd}|D]}|d|jd7}q(|Sr')rr filter_typesrrrrrr(r"r$r%erased_content+s z*DefaultView.render..erased_contentcsBd}jj|gd}|D]}|d|jd7}q&|S)Nr rrr)rrrr*rrr)Zapp_typerrr!r"r$r%unrestartable_content5s z1DefaultView.render..unrestartable_contentcst}t|}|djj|dtjj|djjtjd|djjtjd| t j dkr| S| dS) NrZ total_countZ session_countrZ static_countrutf8)r rassignrlenrZ count_typerrrenderr majorgetvaluedecode)rviewr"r$r% note_content@sz(DefaultView.render..note_contentz * zSome applications using:)titlerzThese applications manually:zUninstalled applications:z+These applications restarting your session:rz+These applications rebooting your computer:rrblockszYou should restart:) rrallappendrrr outr/Zhas_content_and_titleprintr1)r#r&r)r+r,r6r8r5r$r"r%r1s0          zDefaultView.renderN)__name__ __module__ __qualname__r1r$r$r$r%r sr )Z __future__rrr rZtracer.resources.langrZtracer.resources.applicationsrZtracer.views.note_for_hiddenrZtracer.views.blocksr Ztracer.resources.pycompr sysr rer r$r$r$r%s         views/__pycache__/default.cpython-39.pyc000064400000006556151114232410014174 0ustar00a "ed @sddlmZddlmZddlmZddlmZddlmZddl m Z ddl m Z dd l mZdd lmZdd lZGd d d eZd S))print_function)unicode_literals)View)_) Applications)NoteForHiddenView) BlocksView)StringIO) version_infoNc@seZdZddZdS) DefaultViewcsfdd}fdd}fdd}fdd}fd d }d td |d d td|d d td|d g}jjjr|d td|tjdd |d td|tjdd n|d|itj}|d|| r td| dS)Ncsd}tjdtjdtjdg}jj|d}|D]<}d|j }|j rl|j sl|d |j 7}|d|d 7}q@|S) NSESSIONSTATICERASEDhelperz; z # {}  )rTYPESargs applications with_helpers exclude_typesuniquesortedjoinhelpersZhelper_contains_formatingZhelper_contains_nameformatname)contenttypesr applicationrself8/usr/lib/python3.9/site-packages/tracer/views/default.pywith_helpers_contents   z0DefaultView.render..with_helpers_contentcsFd}jjtjdd}|D]}|d|jd7}q*|SNr rrrr) rrrrrrZwithout_helpersrrrZappsr!r"r$r%without_helpers_content s z3DefaultView.render..without_helpers_contentcsDd}jjtjdgd}|D]}|d|jd7}q(|Sr')rr filter_typesrrrrrr(r"r$r%erased_content+s z*DefaultView.render..erased_contentcsBd}jj|gd}|D]}|d|jd7}q&|S)Nr rrr)rrrr*rrr)Zapp_typerrr!r"r$r%unrestartable_content5s z1DefaultView.render..unrestartable_contentcst}t|}|djj|dtjj|djjtjd|djjtjd| t j dkr| S| dS) NrZ total_countZ session_countrZ static_countrutf8)r rassignrlenrZ count_typerrrenderr majorgetvaluedecode)rviewr"r$r% note_content@sz(DefaultView.render..note_contentz * zSome applications using:)titlerzThese applications manually:zUninstalled applications:z+These applications restarting your session:rz+These applications rebooting your computer:rrblockszYou should restart:) rrallappendrrr outr/Zhas_content_and_titleprintr1)r#r&r)r+r,r6r8r5r$r"r%r1s0          zDefaultView.renderN)__name__ __module__ __qualname__r1r$r$r$r%r sr )Z __future__rrr rZtracer.resources.langrZtracer.resources.applicationsrZtracer.views.note_for_hiddenrZtracer.views.blocksr Ztracer.resources.pycompr sysr rer r$r$r$r%s         views/__pycache__/helper.cpython-39.opt-1.pyc000064400000005150151114232410014753 0ustar00a "en @sDddlmZddlmZddlmZddlmZGdddeZdS) )print_function)unicode_literals)View)_c@seZdZddZddZdS) HelperViewc Cs|dj|jjjd|jjr|dj|jjjd|dj|jjjd|dj|jjjd|jjj r|d j|jjj d j d n|d j|jjjdd }d }|jj D]R}||dj|jjj| |j |jdd}|d7}|dkr|dqq|jjjd kr4|d||jjjsJ|jjr|d|djtdd|jjs|dj|jjjdnl|jjr|dtd|jjnD|jjjD]}|dj|dq|jjjr|d|jjjdS)Nz * {app_name})app_namez Package: {pkg_name})pkg_namez" Description: {pkg_description})Zpkg_descriptionz Type: {type})typez Executable: {executable}r) executablez: Package: {app_name} is not provided by any packagez State: z={app_name} has been started by {user} {time} ago. PID - {pid})rusertimepidz rz ...z {title}:zHow to restart)titlez+ {app_name} does not need restartingz z%It's a part of application called {0}z {how_to_restart})Zhow_to_restartz - )printformatargsZ applicationnamepackage descriptionr capitalizeZaffected_instancesZexe processesusernameZstr_started_agorverboserender_affected_byhelperZaffectsr affected_byZhelpersZnote)selfindentiprocessrr#7/usr/lib/python3.9/site-packages/tracer/views/helper.pyrender sL           zHelperView.rendercCsd}d}||tddt|jjtkrH||||jjdSt}|jjD]}|}||jjvr|||d| |j |d7}|j D]t}|j |vs|dkr||||j | |j |jjj dkrq|d7}|jD]}||||q|d8}qqVdS)Nz z Affected by:z {0} ({1})r)rrr rrstrsetrrrrZpackagesaddrfiles)rZ default_levelr Zprinted_packagesr"Z indent_levelrfiler#r#r$r<s,      zHelperView.render_affected_byN)__name__ __module__ __qualname__r%rr#r#r#r$rs3rN)Z __future__rrrrZtracer.resources.langrrr#r#r#r$s    views/__pycache__/helper.cpython-39.pyc000064400000005150151114232410014014 0ustar00a "en @sDddlmZddlmZddlmZddlmZGdddeZdS) )print_function)unicode_literals)View)_c@seZdZddZddZdS) HelperViewc Cs|dj|jjjd|jjr|dj|jjjd|dj|jjjd|dj|jjjd|jjj r|d j|jjj d j d n|d j|jjjdd }d }|jj D]R}||dj|jjj| |j |jdd}|d7}|dkr|dqq|jjjd kr4|d||jjjsJ|jjr|d|djtdd|jjs|dj|jjjdnl|jjr|dtd|jjnD|jjjD]}|dj|dq|jjjr|d|jjjdS)Nz * {app_name})app_namez Package: {pkg_name})pkg_namez" Description: {pkg_description})Zpkg_descriptionz Type: {type})typez Executable: {executable}r) executablez: Package: {app_name} is not provided by any packagez State: z={app_name} has been started by {user} {time} ago. PID - {pid})rusertimepidz rz ...z {title}:zHow to restart)titlez+ {app_name} does not need restartingz z%It's a part of application called {0}z {how_to_restart})Zhow_to_restartz - )printformatargsZ applicationnamepackage descriptionr capitalizeZaffected_instancesZexe processesusernameZstr_started_agorverboserender_affected_byhelperZaffectsr affected_byZhelpersZnote)selfindentiprocessrr#7/usr/lib/python3.9/site-packages/tracer/views/helper.pyrender sL           zHelperView.rendercCsd}d}||tddt|jjtkrH||||jjdSt}|jjD]}|}||jjvr|||d| |j |d7}|j D]t}|j |vs|dkr||||j | |j |jjj dkrq|d7}|jD]}||||q|d8}qqVdS)Nz z Affected by:z {0} ({1})r)rrr rrstrsetrrrrZpackagesaddrfiles)rZ default_levelr Zprinted_packagesr"Z indent_levelrfiler#r#r$r<s,      zHelperView.render_affected_byN)__name__ __module__ __qualname__r%rr#r#r#r$rs3rN)Z __future__rrrrZtracer.resources.langrrr#r#r#r$s    views/__pycache__/interactive.cpython-39.opt-1.pyc000064400000002142151114232410016007 0ustar00a "eV@sDddlmZddlmZddlmZddlmZGdddeZdS) )unicode_literals)View)_)NoteForHiddenViewc@seZdZddZdS)InteractiveViewcCs|jjrttdd}ttt|jj}|jjD]2}d||d}td||j|d7}q4|jjj s|jjr|jj s|jj rtdt }| d|jj| d|jj| d |jj | d |jj |dS) NzYou should restart:rz[{0}]z{} {}args total_count session_count static_count)r Z applicationsprintrlenstrformatljustnameallr r rZassignr render)selfidigitsZ applicationnviewrs    views/__pycache__/interactive.cpython-39.pyc000064400000002142151114232410015050 0ustar00a "eV@sDddlmZddlmZddlmZddlmZGdddeZdS) )unicode_literals)View)_)NoteForHiddenViewc@seZdZddZdS)InteractiveViewcCs|jjrttdd}ttt|jj}|jjD]2}d||d}td||j|d7}q4|jjj s|jjr|jj s|jj rtdt }| d|jj| d|jj| d |jj | d |jj |dS) NzYou should restart:rz[{0}]z{} {}args total_count session_count static_count)r Z applicationsprintrlenstrformatljustnameallr r rZassignr render)selfidigitsZ applicationnviewrs    views/__pycache__/note_for_hidden.cpython-39.opt-1.pyc000064400000001754151114232410016630 0ustar00a "e@s8ddlmZddlmZddlmZGdddeZdS))print_function)View)_c@seZdZddZdS)NoteForHiddenViewcCs|jjjs|jjdks"|jjdkr|jj|jj|jjkrJ|tdn|td|jjdkr|dtd|jj|jjdkr|dtd|jjdS)Nrz There are:zAdditionally, there are:z - zU{0} processes requiring restart of your session (i.e. Logging out & Logging in again)z{0} processes requiring reboot)argsquietZ session_countZ static_countZ total_countprintrformat)selfr @/usr/lib/python3.9/site-packages/tracer/views/note_for_hidden.pyrenders"  zNoteForHiddenView.renderN)__name__ __module__ __qualname__rr r r r rsrN)Z __future__rrZtracer.resources.langrrr r r r s   views/__pycache__/note_for_hidden.cpython-39.pyc000064400000001754151114232410015671 0ustar00a "e@s8ddlmZddlmZddlmZGdddeZdS))print_function)View)_c@seZdZddZdS)NoteForHiddenViewcCs|jjjs|jjdks"|jjdkr|jj|jj|jjkrJ|tdn|td|jjdkr|dtd|jj|jjdkr|dtd|jjdS)Nrz There are:zAdditionally, there are:z - zU{0} processes requiring restart of your session (i.e. Logging out & Logging in again)z{0} processes requiring reboot)argsquietZ session_countZ static_countZ total_countprintrformat)selfr @/usr/lib/python3.9/site-packages/tracer/views/note_for_hidden.pyrenders"  zNoteForHiddenView.renderN)__name__ __module__ __qualname__rr r r r rsrN)Z __future__rrZtracer.resources.langrrr r r r s   views/resource/__pycache__/__init__.cpython-39.opt-1.pyc000064400000000235151114232410017061 0ustar00a "e@sdS)NrrrB/usr/lib/python3.9/site-packages/tracer/views/resource/__init__.pyviews/resource/__pycache__/__init__.cpython-39.pyc000064400000000235151114232410016122 0ustar00a "e@sdS)NrrrB/usr/lib/python3.9/site-packages/tracer/views/resource/__init__.pyviews/resource/__pycache__/applications.cpython-39.opt-1.pyc000064400000001572151114232410020015 0ustar00a "e@s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS)ApplicationsViewcCsRd}t|ddddtd|jjD]$}t||j|j|j|jpFdq(dS)Nz{0:<40}{1:<20}{2:<10}{3:<50}Z ApplicationTypeIgnoreZHelperzx------------------------------------------------------------------------------------------------------------------------)printformatargsZ applicationsnametypeignorehelper)selflineZ applicationrF/usr/lib/python3.9/site-packages/tracer/views/resource/applications.pyrenders  zApplicationsView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrrs  views/resource/__pycache__/applications.cpython-39.pyc000064400000001572151114232410017056 0ustar00a "e@s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS)ApplicationsViewcCsRd}t|ddddtd|jjD]$}t||j|j|j|jpFdq(dS)Nz{0:<40}{1:<20}{2:<10}{3:<50}Z ApplicationTypeIgnoreZHelperzx------------------------------------------------------------------------------------------------------------------------)printformatargsZ applicationsnametypeignorehelper)selflineZ applicationrF/usr/lib/python3.9/site-packages/tracer/views/resource/applications.pyrenders  zApplicationsView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrrs  views/resource/__pycache__/packages.cpython-39.opt-1.pyc000064400000001576151114232410017111 0ustar00a "e@s8ddlmZddlmZddlmZGdddeZdS))unicode_literals)View)datetimec@seZdZddZdS) PackagesViewcCsdd}t|dddtd|jjD]8}t|j}|d}|d}t||||jq&dS)Nz{0: <15}{1: <10}{2: <40}ZDateZTimez Package namez7-------------------------------------------------------z%Y-%m-%dz%H:%M) printformatargsZpackagesrZ fromtimestampmodifiedstrftimename)selflinepackager datetimerB/usr/lib/python3.9/site-packages/tracer/views/resource/packages.pyrenders    zPackagesView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrrs   views/resource/__pycache__/packages.cpython-39.pyc000064400000001576151114232410016152 0ustar00a "e@s8ddlmZddlmZddlmZGdddeZdS))unicode_literals)View)datetimec@seZdZddZdS) PackagesViewcCsdd}t|dddtd|jjD]8}t|j}|d}|d}t||||jq&dS)Nz{0: <15}{1: <10}{2: <40}ZDateZTimez Package namez7-------------------------------------------------------z%Y-%m-%dz%H:%M) printformatargsZpackagesrZ fromtimestampmodifiedstrftimename)selflinepackager datetimerB/usr/lib/python3.9/site-packages/tracer/views/resource/packages.pyrenders    zPackagesView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrrs   views/resource/__pycache__/processes.cpython-39.opt-1.pyc000064400000001565151114232410017337 0ustar00a "e@s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS) ProcessesViewc CsXd}t|ddddtd|jjdD]$}t||j|j||q.dS)Nz{0:<10}{1:<20}{2:<20}{3:<10}ZPIDz Time runningZUserZProcesszd----------------------------------------------------------------------------------------------------Z create_time) printformatargsZ processessortedpidZstr_started_agousernamename)selflineZprocessrC/usr/lib/python3.9/site-packages/tracer/views/resource/processes.pyrenders zProcessesView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrs  views/resource/__pycache__/processes.cpython-39.pyc000064400000001565151114232410016400 0ustar00a "e@s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS) ProcessesViewc CsXd}t|ddddtd|jjdD]$}t||j|j||q.dS)Nz{0:<10}{1:<20}{2:<20}{3:<10}ZPIDz Time runningZUserZProcesszd----------------------------------------------------------------------------------------------------Z create_time) printformatargsZ processessortedpidZstr_started_agousernamename)selflineZprocessrC/usr/lib/python3.9/site-packages/tracer/views/resource/processes.pyrenders zProcessesView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrs  views/resource/__pycache__/rules.cpython-39.opt-1.pyc000064400000001320151114232410016450 0ustar00a "e @s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS) RulesViewcCsBd}t|ddtd|jjD]}t||j|jq$dS)Nz{0:<40}{1:<10}ZRuleActionz7-------------------------------------------------------)printformatargsZrulesnameaction)selflineZruler?/usr/lib/python3.9/site-packages/tracer/views/resource/rules.pyrenders  zRulesView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrs  views/resource/__pycache__/rules.cpython-39.pyc000064400000001320151114232410015511 0ustar00a "e @s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS) RulesViewcCsBd}t|ddtd|jjD]}t||j|jq$dS)Nz{0:<40}{1:<10}ZRuleActionz7-------------------------------------------------------)printformatargsZrulesnameaction)selflineZruler?/usr/lib/python3.9/site-packages/tracer/views/resource/rules.pyrenders  zRulesView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrs  views/resource/__pycache__/system.cpython-39.opt-1.pyc000064400000002047151114232410016651 0ustar00a "e@s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS) SystemViewcCsd}t|d|jjt|d|jjt|dd|jjt|d|jjt|d|jjt|d|jj t |jj d krt|d |jj td t|d |jj t|d |jj t|d|jjdS)Nz {0:<20}{1}zPython:z Distribution:zPackage Manager:z, z Init system:zUptime:zUser:zUsers:zTracer version:zRules:z Applications:)printformatargsZpythonZ distributionjoinZpackage_managersinitZuptimeuserlenZusersversionZ rules_countZapplications_count)selfliner@/usr/lib/python3.9/site-packages/tracer/views/resource/system.pyrenderszSystemView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrrs  views/resource/__pycache__/system.cpython-39.pyc000064400000002047151114232410015712 0ustar00a "e@s,ddlmZddlmZGdddeZdS))unicode_literals)Viewc@seZdZddZdS) SystemViewcCsd}t|d|jjt|d|jjt|dd|jjt|d|jjt|d|jjt|d|jj t |jj d krt|d |jj td t|d |jj t|d |jj t|d|jjdS)Nz {0:<20}{1}zPython:z Distribution:zPackage Manager:z, z Init system:zUptime:zUser:zUsers:zTracer version:zRules:z Applications:)printformatargsZpythonZ distributionjoinZpackage_managersinitZuptimeuserlenZusersversionZ rules_countZapplications_count)selfliner@/usr/lib/python3.9/site-packages/tracer/views/resource/system.pyrenderszSystemView.renderN)__name__ __module__ __qualname__rrrrrrsrN)Z __future__rrrrrrrrs  views/resource/__init__.py000064400000000000151114232410011621 0ustar00views/resource/applications.py000064400000000600151114232410012556 0ustar00from __future__ import unicode_literals from .. import View class ApplicationsView(View): def render(self): line = "{0:<40}{1:<20}{2:<10}{3:<50}" print(line.format("Application", "Type", "Ignore", "Helper")) print(120 * "-") for application in self.args.applications: print(line.format(application.name, application.type, application.ignore, application.helper or "")) views/resource/packages.py000064400000000716151114232410011656 0ustar00from __future__ import unicode_literals from .. import View from datetime import datetime class PackagesView(View): def render(self): line = "{0: <15}{1: <10}{2: <40}" print(line.format("Date", "Time", "Package name")) print(55 * "-") for package in self.args.packages: modified = datetime.fromtimestamp(package.modified) date = modified.strftime('%Y-%m-%d') time = modified.strftime('%H:%M') print(line.format(date, time, package.name)) views/resource/processes.py000064400000000603151114232410012101 0ustar00from __future__ import unicode_literals from .. import View class ProcessesView(View): def render(self): line = "{0:<10}{1:<20}{2:<20}{3:<10}" print(line.format("PID", "Time running", "User", "Process")) print(100 * "-") for process in self.args.processes.sorted("create_time"): print(line.format(process.pid, process.str_started_ago, process.username(), process.name())) views/resource/rules.py000064400000000411151114232410011222 0ustar00from __future__ import unicode_literals from .. import View class RulesView(View): def render(self): line = "{0:<40}{1:<10}" print(line.format("Rule", "Action")) print(55 * "-") for rule in self.args.rules: print(line.format(rule.name, rule.action)) views/resource/system.py000064400000001350151114232410011417 0ustar00from __future__ import unicode_literals from .. import View class SystemView(View): def render(self): line = "{0:<20}{1}" print(line.format("Python:", self.args.python)) print(line.format("Distribution:", self.args.distribution)) print(line.format("Package Manager:", ", ".join(self.args.package_managers))) print(line.format("Init system:", self.args.init)) print(line.format("Uptime:", self.args.uptime)) print(line.format("User:", self.args.user)) if len(self.args.users) > 1: print(line.format("Users:", self.args.users)) print("") print(line.format("Tracer version:", self.args.version)) print(line.format("Rules:", self.args.rules_count)) print(line.format("Applications:", self.args.applications_count)) views/__init__.py000064400000001005151114232410010000 0ustar00from __future__ import print_function from __future__ import unicode_literals from sys import __stdout__, version_info class Arguments(object): pass class View(object): args = Arguments() out = None def __init__(self, out=__stdout__): self.out = out def assign(self, key, value): self.args.__dict__[key] = value def get(self, key): return self.args.__dict__[key] def print(self, text, end=None): if version_info.major == 2: text = text.encode("utf8") print(text, end=end, file=self.out) views/blocks.py000064400000002040151114232410007516 0ustar00from __future__ import print_function from __future__ import unicode_literals from . import View import sys class BlocksView(View): """ Assign ``blocks`` with this list [ { "title": "...", "content": "some text", }, ... ] """ def render(self): for index, block in enumerate(self.args.blocks): if block["content"]: if "title" in block: self.print(block["title"]) self.print(block["content"], end="") if self.next(index): self.print("") def next(self, index): """Return True if there is any nonempty block after given index""" for block in self.args.blocks[index+1:]: if block["content"]: return True return False def has_content_and_title(self): """Return True if at least one block's content & title is not empty""" for block in self.args.blocks[0:]: if block["content"] and "title" in block.keys(): if block["title"]: return True return False views/default.py000064400000006144151114232410007676 0ustar00from __future__ import print_function from __future__ import unicode_literals from . import View from tracer.resources.lang import _ from tracer.resources.applications import Applications from tracer.views.note_for_hidden import NoteForHiddenView from tracer.views.blocks import BlocksView from tracer.resources.pycomp import StringIO from sys import version_info import re class DefaultView(View): def render(self): def with_helpers_content(): content = "" types = [Applications.TYPES["SESSION"], Applications.TYPES["STATIC"], Applications.TYPES["ERASED"]] applications = (self.args.applications .with_helpers() .exclude_types(types) .unique() .sorted("helper")) for application in applications: helpers = "; ".join(application.helpers) if application.helper_contains_formating and not application.helper_contains_name: helpers += " # {}".format(application.name) content += " " + helpers + "\n" return content def without_helpers_content(): content = "" apps = (self.args.applications .exclude_types(Applications.TYPES["ERASED"]) .unique() .without_helpers() .sorted("name")) for application in apps: content += " " + application.name + "\n" return content def erased_content(): content = "" apps = (self.args.applications .filter_types([Applications.TYPES["ERASED"]]) .unique() .sorted("name")) for application in apps: content += " " + application.name + "\n" return content def unrestartable_content(app_type): content = "" applications = (self.args.applications .with_helpers() .filter_types([app_type]) .unique() .sorted("name")) for application in applications: content += " " + application.name + "\n" return content def note_content(): content = StringIO() view = NoteForHiddenView(content) view.assign("args", self.args.args) view.assign("total_count", len(self.args.applications)) view.assign("session_count", self.args.applications.count_type(Applications.TYPES["SESSION"])) view.assign("static_count", self.args.applications.count_type(Applications.TYPES["STATIC"])) view.render() return content.getvalue() if version_info.major >= 3 else content.getvalue().decode("utf8") blocks = [ {"title": " * " + _("Some applications using:"), "content": with_helpers_content()}, {"title": " * " + _("These applications manually:"), "content": without_helpers_content()}, {"title": " * " + _("Uninstalled applications:"), "content": erased_content()}, ] if self.args.args.all: blocks.append({ "title": " * " + _("These applications restarting your session:"), "content": unrestartable_content(Applications.TYPES["SESSION"]) }) blocks.append({ "title": " * " + _("These applications rebooting your computer:"), "content": unrestartable_content(Applications.TYPES["STATIC"]) }) else: blocks.append({"content": note_content()}) view = BlocksView(self.out) view.assign("blocks", blocks) if view.has_content_and_title(): self.print(_("You should restart:")) view.render() views/helper.py000064400000005556151114232410007537 0ustar00from __future__ import print_function from __future__ import unicode_literals from . import View from tracer.resources.lang import _ class HelperView(View): def render(self): self.print("* {app_name}".format(app_name=self.args.application.name)) # Package informations if self.args.package: self.print(" Package: {pkg_name}" .format(pkg_name=self.args.package.name)) self.print(" Description: {pkg_description}" .format(pkg_description=self.args.package.description)) self.print(" Type: {type}" .format(type=self.args.application.type.capitalize())) if self.args.application.affected_instances: self.print(" Executable: {executable}".format(executable=self.args.application.affected_instances[0].exe)) else: self.print(" Package: {app_name} is not provided by any package" .format(app_name=self.args.application.name)) # State indent = " State: " i = 0 for process in self.args.processes: self.print(indent + "{app_name} has been started by {user} {time} ago. PID - {pid}".format( app_name=self.args.application.name, user=process.username(), time=process.str_started_ago, pid=process.pid )) indent = " " i += 1 if i >= 3: self.print(" ...") break # Affected by if self.args.args.verbose > 0: self.print("") self.render_affected_by() # How to restart if self.args.application.helper or self.args.affects: self.print("") self.print(" {title}:".format(title=_('How to restart'))) if not self.args.affected_by: self.print(" {app_name} does not need restarting".format(app_name=self.args.application.name)) elif self.args.affects: self.print(" " + _("It's a part of application called {0}").format(self.args.affects)) else: for helper in self.args.application.helpers: self.print(" {how_to_restart}".format(how_to_restart=helper)) if self.args.application.note: self.print("\n - " + self.args.application.note) def render_affected_by(self): default_level = 2 indent = " " self.print(indent + _("Affected by") + ":") if type(self.args.affected_by) == str: self.print(default_level * indent + self.args.affected_by) return printed_packages = set() for process in self.args.affected_by: indent_level = default_level if process not in self.args.processes: self.print(indent_level * indent + "{0} ({1})".format(process.name(), process.pid)) indent_level += 1 for package in process.packages: if package.name not in printed_packages or indent_level > 2: self.print(indent_level * indent + package.name) printed_packages.add(package.name) if self.args.args.verbose < 2: continue indent_level += 1 for file in package.files: self.print(indent_level * indent + file) indent_level -= 1 views/interactive.py000064400000001526151114232410010566 0ustar00from __future__ import unicode_literals from . import View from tracer.resources.lang import _ from tracer.views.note_for_hidden import NoteForHiddenView class InteractiveView(View): def render(self): if self.args.applications: print(_("You should restart:")) i = 1 digits = len(str(len(self.args.applications))) for application in self.args.applications: n = "[{0}]".format(i).ljust(digits + 2) print("{} {}".format(n, application.name)) i += 1 if not self.args.args.all: if self.args.applications and (self.args.session_count or self.args.static_count): print("") view = NoteForHiddenView() view.assign("args", self.args.args) view.assign("total_count", self.args.total_count) view.assign("session_count", self.args.session_count) view.assign("static_count", self.args.static_count) view.render() views/note_for_hidden.py000064400000001347151114232410011400 0ustar00from __future__ import print_function from . import View from tracer.resources.lang import _ class NoteForHiddenView(View): def render(self): if not self.args.args.quiet and (self.args.session_count > 0 or self.args.static_count > 0): if self.args.session_count + self.args.static_count == self.args.total_count: self.print(_("There are:")) else: self.print(_("Additionally, there are:")) if self.args.session_count > 0: self.print(" - " + \ _("{0} processes requiring restart of your session (i.e. Logging out & Logging in again)")\ .format(self.args.session_count) ) if self.args.static_count > 0: self.print(" - " + _("{0} processes requiring reboot").format(self.args.static_count)) __init__.py000064400000000421151114232410006644 0ustar00from __future__ import absolute_import from tracer.query import Query from tracer.resources.package import Package from tracer.resources.applications import Application from tracer.resources.processes import Process __all__ = [ Query, Package, Application, Process, ]hooks.py000064400000004073151114232410006237 0ustar00# -*- coding: utf-8 -*- # hooks.py # Module providing hooks functionality # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # import os from tracer.paths import HOOKS_DIRS from tracer.resources.pycomp import load_source _hooks = {} class HooksObserver(object): """ Provides interface for calling user hooks When initializing, loads all hooks located in HOOKS_DIRS. Then it can called with application name as argument. Observer ensures calling all hooks defined for the application. """ def __init__(self): _register_hooks() def __call__(self, app): if app not in _hooks: return [f() for f in _hooks[app]] def match(apps): """ Decorator for tracer hooks. Example:: from tracer import hooks @hooks.match("foo") def hook_app(): print("Hey, application foo was found") .. note:: You can match multiple applications by calling ``@hooks.match`` with list of them. """ def decorator(f): for app in apps if type(apps) == list else [apps]: if app not in _hooks: _hooks[app] = [] _hooks[app].append(f) return f return decorator def _register_hooks(): # see search function here # http://stackoverflow.com/a/4788700/3285282 for hook_dir in HOOKS_DIRS: for root, dirs, files in os.walk(hook_dir): for fname in files: modname = os.path.splitext(fname)[0] try: load_source(modname, os.path.join(root, fname)) except Exception: continue main.py000064400000004003151114232410006031 0ustar00#-*- coding: utf-8 -*- # main.py # Tracer finds outdated running applications in your system # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from __future__ import print_function import os import sys import time from tracer.resources.router import Router from tracer.resources.args_parser import parser from tracer.resources.package import Package from tracer.resources.exceptions import ( TracerError, UnsupportedDistribution, PathNotFound, LockedDatabase, DatabasePermissions, ) from tracer.resources.lang import _ def run(): args = parser.parse_args() # If there is something on stdin (that means piped into tracer) stdin_packages = [] if not sys.stdin.isatty() and "SSH_CONNECTION" not in os.environ: stdin_packages = sys.stdin.readline().split() # All input packages enchanced by actual time (as modified time) packages = [] for package in args.packages + args.pkgs + stdin_packages: packages.append(Package(package, time.time() if args.now else None)) try: router = Router(args, packages) return router.dispatch() except (UnsupportedDistribution, PathNotFound, LockedDatabase) as ex: ex.print() exit(1) except DatabasePermissions as ex: ex.print() print(_("You will probably need to run tracer as root")) exit(1) except TracerError as ex: ex.print() exit(1) except (KeyboardInterrupt, EOFError): print("") paths.py000064400000003075151114232410006234 0ustar00#-*- coding: utf-8 -*- # paths.py # Module for defining paths to project directories. They are different when # project is developed on git and when project is installed as a linux package # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # import os from os.path import dirname, realpath, expanduser from tracer.resources.system import System def __(paths): for path in paths: if os.path.isdir(path): return path return paths[0] PROJECT_DIR = dirname(dirname(realpath(__file__))) DATA_DIR = __([ PROJECT_DIR + '/' + 'data', '/usr/share/tracer', ]) USER_CONFIG_DIRS = [ '/etc/tracer', ] HOOKS_DIRS = [ '/etc/tracer/hooks', ] LANG_DIR = __([ PROJECT_DIR + '/build/' + 'locale', '/usr/share/locale', ]) try: user = System.user() USER_CONFIG_DIRS.append(expanduser('~' + user) + '/.config/tracer') HOOKS_DIRS.append(expanduser('~' + user) + '/.config/tracer/hooks') except OSError: pass query.py000064400000004274151114232410006264 0ustar00#-*- coding: utf-8 -*- # query.py # Module providing querying operations to Tracer API # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # from tracer.resources.tracer import Tracer from tracer.resources.system import System from tracer.resources.rules import Rules from tracer.resources.applications import Applications from tracer.resources.memory import dump_memory class Query(object): """ Provide API for Tracer querying operations. They are executed kind of lazily, so running the operation will return just an wrapper class with ``get()`` method. Example:: from tracer.query import Query q = Query() q.affected_applications().get() .. note:: Some querying methods can require root permissions """ def __init__(self, tracer=Tracer): self._tracer = tracer(System.package_manager(), Rules, Applications, dump_memory) def from_packages(self, packages): """List of ``Package`` that only should be traced""" self._tracer.specified_packages = packages return self def now(self): """ Pretend that specified packages have been updated just now. Benefit of this is absolutely no need for openning the package history database """ self._tracer.now = True return self def affected_applications(self, user=None): """ Return list of applications which use some outdated files """ return Lazy(self._tracer.trace_affected, {"user": user}) class Lazy(object): def __init__(self, method, kwargs): self._method = method self._kwargs = kwargs def get(self): return self._method(**self._kwargs) version.py000064400000001571151114232410006601 0ustar00#-*- coding: utf-8 -*- # version.py # Version module generated with tito # WARNING: !! Do not edit this file !! # # Copyright (C) 2016 Jakub Kadlcik # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # __version__ = '1.1' __release__ = '1'