Skip to content

Commit

Permalink
Merge pull request #4 from you-n-g/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
you-n-g authored Sep 12, 2020
2 parents fe5e181 + 78ff2e0 commit 53265b0
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 20 deletions.
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,42 @@ This package is under development. We will release it soon in the future.

# Installation

[fzf](https://github.com/junegunn/fzf) is required
<!-- [fzf](https://github.com/junegunn/fzf) is required -->
```shell
pip install wan # TODO: upload this to pip source
```

## config

Please config your [notifiers](https://github.com/liiight/notifiers).
`wan` will read the setting in ` ~/.dotfiles/.notifers.yaml` as the arguments for notifiers.

Here is a config example of telegram
```yaml
provider: telegram
kwargs:
chat_id: <Your Chat id from `@myidbot` by sending `/getid`>
token: <Your token from `@BotFather` by sending `/newbot`>
```
Other configs:
```yaml
log_level: DEBUG # the default level is INFO
```
# Usage
## Use in python code
* Call the function in python code directly.
```python
<Your code which takes a lot of time>
from wan import ntf; ntf('Finished')
```

* Call the function in shell directly
```shell
> sleep 10 ; wan ntf sleep finished
```

2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

## Telegram
* get `token` from `@BotFather` by sending `/newbot`
* send `/start` to your chatbot to start charting.
* send `/start` to your chatbot to start chatting.
* Get `chat_id` from `@myidbot` by sending `/getid`
25 changes: 25 additions & 0 deletions docs/RoadMap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Plan

## Development
- [ ] Start command after another process ends or become idle
- [ ] Draw the workflow.
- [ ] auto find my running process
- [ ] Run and wait the command
- [ ] GIF to demonstrate the usage of WAN
- [ ] documents(rst??)
- [ ] Opensource Licence?
- [ ] travies - CI
- [ ] wait until system become idle

### optional
- [ ] Can we make fzf installed automatically?

## Release
- [ ] pip release
- [ ] readthedocs???



## Promotion
- [ ] stackoverflow
- [ ] zhihu
78 changes: 62 additions & 16 deletions wan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
from .utils import get_pid_via_fzf
import psutil
import time
import sys
import os


class Notifier:
def __init__(self, config_path: str = '~/.dotfiles/.notifers.yaml'):
def __init__(self, config_path: str = '~/.dotfiles/.notifiers.yaml'):
"""__init__.
Parameters
Expand All @@ -24,6 +26,15 @@ def __init__(self, config_path: str = '~/.dotfiles/.notifers.yaml'):
chat_id: <Your Chat ID>
token: <Your token>
```
If you need proxy for your provider, please use the config below.
The env will be updated when running `ntf` method
[This solution](https://github.com/liiight/notifiers/issues/236) is proposed by notifiers
```
env:
HTTP_PROXY: 'http://IP:PORT'
HTTPS_PROXY: 'http://IP:PORT'
```
"""
# TODO: DEBUG mode
path = Path(config_path).expanduser()
Expand All @@ -34,39 +45,68 @@ def __init__(self, config_path: str = '~/.dotfiles/.notifers.yaml'):
else:
with path.open() as f:
self.config = yaml.load(f, Loader=yaml.FullLoader)
logger.remove()
log_level = self.config.get('log_level', 'INFO')
logger.add(sys.stderr, level=log_level)
logger.debug(f"log level: {log_level}")
self._provider = get_notifier(self.config['provider'])
kwargs = self.config['kwargs']
self._ntf = partial(self._provider.notify, **kwargs)

def ntf(self, message):
self.env = self.config.get('env', {})

def ntf(self, *messages):
message = " ".join(messages)
logger.debug("Sending message: {}".format(message))
if len(message) == 0:
logger.warning("Blank message.")

# set proxy if needed
env_back = os.environ.copy()
os.environ.update(self.env)
self._ntf(message=message)
for k, v in self.env.items():
if k not in env_back:
del os.environ[k]
else:
os.environ[k] = env_back[k]

def wait(self, pid=None, message=None, idle=False, patience=20):
@staticmethod
def _get_process_info(pid):
process_info = ":"
try:
p = psutil.Process(pid)
except psutil.NoSuchProcess:
process_info = ""
else:
process_info = ":" + ' '.join(p.cmdline())
return process_info

def wait(self, pid=None, message=None, idle=False, patience=20, sleep=3):
"""wait.
wati the proces to stop or idle
Parameters
----------
pid :
pid
message :
message
idle :
will it notify me if the process become idle
patience :
How many idle status is ignored before reguard the process as stopped
sleep :
sleep
"""
logger.debug(f"Idle: {idle}")

process_info = ":"
if pid is None:
pid = get_pid_via_fzf()
if pid is None:
logger.info('No process selected')
logger.info('No process selected, You can used --pid to specify the process')
return

try:
p = psutil.Process(pid)
except psutil.NoSuchProcess:
process_info = ""
else:
process_info = ":" + ' '.join(p.cmdline())
process_info = self._get_process_info(pid)

logger.info(f'Process[{pid}{process_info}] selected')

Expand All @@ -75,24 +115,30 @@ def wait(self, pid=None, message=None, idle=False, patience=20):
try:
p = psutil.Process(pid)
except psutil.NoSuchProcess:
logger.debug(f'The process[PID] has ended')
logger.info(f'The process[PID] has ended')
break
else:
# TODO: get the information of subprocess
# TODO: get the information of subprocesses
p_status = p.status()
logger.debug(f'status: {p_status}, patience: {cp}')
if idle and p_status not in {psutil.STATUS_RUNNING, psutil.STATUS_DISK_SLEEP}:
cp += 1
if cp > patience:
logger.debug(f'The process is not running, status: {p_status}')
logger.info(f'The process is not running, status: {p_status}')
break
else:
cp = 0
time.sleep(2)
time.sleep(sleep)
if message is None:
message = f'The Process[{pid}{process_info}] has stopped or become idle now.'
self.ntf(message)


def ntf(message):
# notify with the call stack
Notifier().ntf(message)


def run():
fire.Fire(Notifier)

Expand Down
17 changes: 15 additions & 2 deletions wan/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import subprocess
from iterfzf import iterfzf
from loguru import logger
import os
import stat


def iter_ps():
Expand All @@ -14,8 +17,18 @@ def get_pid_from_line(line):


def get_pid_via_fzf(exact=True):
# TODO: make it can be selected with full match
return get_pid_from_line(iterfzf(iter_ps(), multi=False, exact=exact))
try:
# FIXME: This is a bug from iterfzf. The fzf may not be executable
selected_line = iterfzf(iter_ps(), multi=False, exact=exact)
except PermissionError as e:
try:
os.chmod(e.filename, os.stat(e.filename).st_mode | stat.S_IEXEC)
except PermissionError:
logger.error(f'Please make {e.filename} executable(e.g `chmod a+x {e.filename}`).')
return None
else:
selected_line = iterfzf(iter_ps(), multi=False, exact=exact)
return get_pid_from_line(selected_line)


if __name__ == "__main__":
Expand Down

0 comments on commit 53265b0

Please sign in to comment.