oreoreCLIを作って最速で静的ホスティングを行う

[3-shake Advent Calendar2022](https://qiita.com/advent-calendar/2022/3-shake)の22日目です。

## 初めに
自分は最近flutterやReactなどで作業をしている時にふと思うことがあります
GO「よし一旦できたから成果物webに上げてみるか〜」
GO「えっとS3作ってポリシー設定して成果物ドラック&ドロップして...めんどくさい」
そうなんですこの作業が毎回億劫なんです！！
え、CICDつくればいいじゃんって？さすがにそこまで構築するのはオーバーすぎる
**そうだ俺俺CLIつくろう！！**

## 前提条件
- 詳しいコードの説明はしません
- Pythonを知っている方向けです

## ディレクトリ構造

```
oreorecli
├── code
│   ├── __init__.py
│   └── core.py
└── setup.py
```

### それぞれのファイルの説明

#### code/core.py
ここはCLIで動かしたい実際の処理を記述します。
今回はここでは下記のような実装を行いました
- S3バケットの作成
- 静的ホスティングの設定
- バケットポリシーの付与
- サブコマンドで渡されてきたディレクトリの中身をS3にアップロードする

#### setup.py
ここはCLIの設定を記述する部分です
CLI自体の名前やバージョン、使用するPythonのバージョンなども記載しています


## コード説明

### core.py

```python
import boto3
import json
import time
import argparse
from multiprocessing import Process
import subprocess

# サブコマンド定義
p = argparse.ArgumentParser()
p.add_argument('dist', help='公開したいフォルダ')
args = p.parse_args()


def main():

  s3 = boto3.client("s3")
  now_time =int(time.time())

  args_dist = args.dist
  target = '=' 
  idx = args_dist.find(target)
  fix_dist = args_dist[idx+len(target):]


  #バケットポリシー定義
  bucket_policy = {
      'Version': '2012-10-17',
      'Statement': [{
          'Sid': 'AddPerm',
          'Effect': 'Allow',
          'Principal': '*',
          'Action': ['s3:GetObject'],
          'Resource': f'arn:aws:s3:::{str(now_time)}/*'
      }]
  }

  # S3バケット作成
  res = s3.create_bucket(ACL="public-read",
                        Bucket=str(now_time),
                        CreateBucketConfiguration={
                          "LocationConstraint": "ap-northeast-1"
                          })

  # S3バケットに静的ホスティング設定
  response = s3.put_bucket_website(
      Bucket=str(now_time),
      WebsiteConfiguration={
          'IndexDocument': {
              'Suffix': 'index.html'
          },
      },
  )
  bucket_policy = json.dumps(bucket_policy)

  s3.put_bucket_policy(Bucket=str(now_time), Policy=bucket_policy)
  
  #引数で渡されたものをS3にアップロード
  cmd_sync =f'aws s3 sync {fix_dist} s3://{str(now_time)}/'
  print("アップロード中です・・・")
  result = subprocess.Popen(cmd_sync.split(" "))
  result.wait()
  print("完了しました")
  print("以下のURLからアクセスできます")
  print(f"http://{str(now_time)}.s3-website-ap-northeast-1.amazonaws.com")


```

ポイント
- S3バケットの名前は被らないようにunixtimeを取得してそちらを名前に使っている
- アップロードする時にプロセスの終了を待って完了したら静的ホスティングのURLをprintしている
- 引数distでローカル上でアップロードしたいフォルダを指定できるようにしている


### setup.py

```python
from setuptools import setup, find_packages
setup(
    name="oreorecli",
    version="0.0.1",
    description="s3で静的ホスティングを行うCLI",
    install_requires=["boto3"],
    author="masaki.go",
    entry_points={
        "console_scripts": [
            "oreorecli=sample.core:main",
        ]
    },
    classifiers=[
        'Programming Language :: Python :: 3.9',
    ]
)

```
ポイント
- install_requiresにしようするパッケージを記載している。今回はboto3
- console_scriptsではどのコマンドを叩いた時にcore.pyのmain関数を動かすかを定義しています

## 実際に叩いてみる
今回はflutterをwebようにビルドして成果物はローカルにあります

```bash
oreorecli dist=web/
アップロード中です・・・
upload: web/favicon.png to s3://1671008872/favicon.png
upload: web/icons/Icon-maskable-192.png to s3://1671008872/icons/Icon-maskable-192.png
upload: web/icons/Icon-192.png to s3://1671008872/icons/Icon-192.png
upload: web/manifest.json to s3://1671008872/manifest.json
upload: web/index.html to s3://1671008872/index.html
upload: web/icons/Icon-maskable-512.png to s3://1671008872/icons/Icon-maskable-512.png
upload: web/icons/Icon-512.png to s3://1671008872/icons/Icon-512.png
完了しました
以下のURLからアクセスできます
http://1671008872.s3-website-ap-northeast-1.amazonaws.com
```

## 最後に
AWSのCLIでよくない？っていう意見は受け付けていません！！！！w

パッケージの配布の仕方などはこちらの記事がとてもよく纏まっていました。
https://www.karakaram.com/how-to-create-python-cli-package/