본문 바로가기
업무 자동화

Alfred workflow 만들기 - intellij 프로젝트를 검색하고 실행까지

by tango0415 2020. 9. 20.

Alfred workflow란?

https://www.alfredapp.com/workflows/

맥 사용자라면 필수 앱으로 빠지지 않고 소개되는 알프레드 앱의 기능 중, Powerpack(유료) 라이선스가 있다면 사용할 수 있는 기능입니다.

간단한 작업이라면 알프레드에서 제공해주는 기능들을 이어 붙임으로써 어떤 Trigger 가 일어나면 연결된 작업들이 순차적으로 수행되게끔 만들 수 있고, 알프레드가 지원해주지 않는 기능도 스크립트를 만들어서 수행시킬 수 있습니다.

업무 자동화에 관심이 많다보니, 큰 서비스 속에서의 개발을 떠나 작고 소소한 것이지만 내가 루틴하게 수행하는 일들을 스크립트로 개발하는 시간을 가집니다.

그 중 제가 하루에 30번 이상도 수행하는 스크립트가 있어서 Alfred workflow 만드는 방법과 같이 소개하려고 합니다.

intellij 프로젝트 검색 후 실행

제가 자주 쓰는 이 workflow는 아래와 같이 동작합니다.

  1. 사용자가 어떤 IDE 를 사용할건지 입력한다 (ij: intellij, py: pycharm, cl: clion)
  2. 사용자가 프로젝트 이름을 검색어로 입력한다
  3. 특정 디렉토리들 하위에 해당 이름을 가진 jetbrain project 디렉토리가 있는지 검색한다
  4. 사용자가 그 중 하나를 선택하면 IDE 로 해당 디렉토리를 열어준다
  5. 성공 알림을 띄운다

IDE가 열려있지 않은 상태에서 바로 특정 프로젝트를 열때도 유용하고, jetbrain IDE는 하나의 window에서 여러 프로젝트를 다룰 수 없기 때문에 여러 프로젝트를 열어서 코드를 봐야할 때도 유용하게 쓰고 있습니다.

workflow 만들기

Blank workflow 생성

검색 기능을 담당할 Script Filter 생성

마우스 우클릭 > Inputs > Script Filter

우선 alfred workflow 에서 각 작업의 input/output 을 알 필요가 있습니다.

input 은 python 스크립트 실행 시에 argv 인자로 넘겨받을 수 있습니다.

ouput 은 기존에는 표준출력에 xml 형태의 텍스트를 출력해주는 방식이였는데 이 방식은 레거시가 되었다고 하고 지금은 json 텍스트를 표준출력 해주면 됩니다.

https://www.alfredapp.com/help/workflows/inputs/script-filter/

https://www.alfredapp.com/help/workflows/inputs/script-filter/json/

우선 검색어를 입력하면 해당 검색어와 icon image 를 보여주는 스크립트이고 아래처럼 keyword 를 입력하고 한칸 띄운 뒤 검색어를 입력하면 python 스크립트에서 sys.argv 로 검색어를 받은 뒤, print 표준 출력으로 json 형태를 출력해주면 하단에 검색된 리스트가 보여집니다.

참고로 workflow 를 만들게 되면 아래의 경로에 디렉토리가 생성되고, 등록한 icon image 이름 등을 확인하고 사용할 수 있습니다. (suffix로 붙는 해쉬값은 다를 수 있습니다)

~/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.FE921C80-4368-40EC-A7E9-EC232B5FC4B9

> ls -alF
total 256
drwxr-xr-x  5 jaekwon  staff    160  9 20 17:00 ./
drwxr-xr-x  7 jaekwon  staff    224  9 20 16:54 ../
-rw-r--r--@ 1 jaekwon  staff  39687  9 20 17:00 3575E4D3-70B9-4D80-BB77-FD73B9C9F170.png
-rw-r--r--  1 jaekwon  staff  81932  9 20 16:54 icon.png
-rw-r--r--  1 jaekwon  staff   2245  9 20 17:08 info.plist

기반은 다 만들었으니 검색 로직을 만들어야 합니다. 검색의 단계를 나눠서 생각해보면

  1. 특정 디렉토리 하위를 조회
  2. 해당 디렉토리가 project 디렉토리인지 확인
  3. 검색어에 일치하는 project 인지 확인

같은 과정이 필요하다고 생각해볼 수 있습니다.

  1. 특정 디렉토리 하위를 조회

내가 프로젝트 디렉토리로 자주 쓰는 곳들을 등록해두면 그 하위에 디렉토리를 loop 돌며 찾아가는 방식으로 구현해볼 수 있습니다.

def search(q, dirname):
    ps = []
    filenames = os.listdir(dirname)
    for i, filename in enumerate(filenames):
        # TODO 2,3 과정을 검증하고 ps 변수에 디렉토리 추가
    return ps
  1. 해당 디렉토리가 project 디렉토리인지 확인

intellij 를 좀 쓰신 분들이라면 intellij 로 프로젝트 디렉토리를 열때 메타데이터나 캐시데이터를 저장하기 위해 .idea 디렉토리가 생긴다는 것을 알고 있을 것입니다. 해당 디렉토리의 유무로 프로젝트 디렉토리인지를 확인할 수 있습니다.

다만 이 경우에 git clone 으로 특정 프로젝트를 다운로드 받은 직후에 한번도 intellij 로 열지 않은 프로젝트 같은 경우는 검색이 안됩니다.

def check_jetbrain_project(path):
    filenames = os.listdir(path)
    for filename in filenames:
        if filename == ".idea":
            return True
    return False
  1. 검색어에 일치하는 project인지 확인

프로젝트의 이름과 디렉토리의 이름이 같다면 디렉토리 이름으로도 찾을 수 있겠지만, 그렇지 않은 프로젝트들도 있을 수 있습니다.

그렇지 않은 프로젝트들은 /.idea/.name 파일로 프로젝트의 이름이 생성되기에 이 정보를 이용할 수 있습니다.

def get_project_name(path):
    name = path.split("/")[-1]
    dotname_path = path + '/.idea/.name'
    if os.path.exists(dotname_path):
        with open(dotname_path, 'r') as file:
            name = file.read().replace('\n', '')
    return name

def search(q, dirname):
    ps = []
    filenames = os.listdir(dirname)
    for i, filename in enumerate(filenames):
        full_path = os.path.join(dirname, filename)
        if os.path.isdir(full_path) and check_jetbrain_project(full_path):
            project_name = get_project_name(full_path)
            if q == "" or filename.find(q) >= 0 or project_name.find(q) >= 0:
                ps.append({
                    "index": i,
                    "project_name": project_name,
                    "dirname": filename,
                    "path": os.path.join(dirname, filename)
                })
    return ps

위 과정을 통해서 검색어에 일치하는 프로젝트 디렉토리들을 찾을 수 있고, 이제 사용자가 선택할 수 있도록 json 형태로 출력해주면 됩니다.

그리고 다음 step에서 해당 디렉토리를 열 수 있게끔 디렉토리 full path를 "arg" 라는 속성으로 넘겨주어야 합니다.

전체 코드는 git repo 참고: github.com/JaekwonHa/alfred-workflow/blob/master/open_project_in_jetbrain/search_script.py

특정 IDE를 실행할 Run Script 생성

마우스 우클릭 > Actions > Run Script

여기서 query 로 인자를 받을 수 있는데, 이는 이전 작업에서 json 데이터 중에 arg 속성으로 넘겨준 값입니다. 여기서는 프로젝트 디렉토리의 full path를 받습니다.

IDEA_PATH 라는 항목이 있는데 intellij 를 실행시켜주는 바이너리 파일의 경로입니다.

tool > Create Command-line Launcher 를 이용해서 생성해줍니다.

성공 알림을 띄워줄 Post Notification 생성

마우스 우클릭 > Outputs > Post Notification

결과

여기까지 진행하시면 디렉토리 이름 or 프로젝트 이름으로 jetbrain 프로젝트 디렉토리들이 검색되게 됩니다.

TIP

  • 디버깅

상단의 벌레 아이콘으로 스크립트의 실행 로그를 확인할 수 있습니다.

이때 주의하실 점은 표준출력으로 로그를 찍게되면 json 형태가 아니라는 에러가 발생하기에 주의해야 합니다.

이상으로 Alfred workflow 를 만들어 보았습니다. 여기서 더 나아가본다면, 많이 검색된 데이터는 우선순위를 더 준다거나, 이전 검색어를 캐시해둔다거나 하는 추가적인 기능들도 생각해볼 수 있겠고 나중에 또 시간이 된다면 개발하고 글로 남겨보겠습니다.