Python Snack 最佳實踐

python snack

瞭解linux的人應該據說過NewtNewt是一個爲RedHat安裝程序而設計的基於文本的窗口開發工具,它是由c語言編寫並不依賴X包,linux下的dialogwhiptail都是基於它。而咱們今天討論的snack則是Newt提供的python接口,redhat的系統都自帶這個模塊,本文就如何使用snack製做僞終端頁面展開講解,並配合代碼展現實現效果。html

前言

爲啥說是最佳實踐呢?由於我使用snack的過程當中,上網查閱相關資料,發現有關信息甚少。偶爾幾篇文章都是處於API或者Demo的級別,而且講的都不全,更別說高級擴展功能了。我正好工做須要給咱們的一個系統作一個終端部署控制檯UI,因此我就使用了python snack來實現,期間不斷新需求,不斷迭代,從基本頁面到增刪改查,再到校驗、再到配置導入、再到進度條等等,不斷的迭代開發讓我對snack不斷地加深認知,它支持的或不支持的我都想辦法一一解決,因此在這把我這段時間的收貨進行總結並分享給須要的人。前端

具體場景

本文實踐的需求是作一個部署控制檯工具,該工具主要分爲三個階段:基礎配置、高級配置和部署進度。基礎配置頁面須要咱們建立一些主機,填寫一些主機的信息,好比IPHostnamePassword,而後高級配置咱們也須要建立一些主機,不過咱們能夠複用基礎設置的主機,因此咱們的工具要支持在高級配置中導入基礎配置的功能,在高級配置中咱們還有一個全局配置,也就是不限於單個主機的配置(其中具體部署原理和是非,我就很少展開贅述,這不是本文的重點)。最後就是進度條頁面,咱們能夠展現部署的過程階段和相關時間信息。vue

deploy console

項目地址: https://github.com/tony-yin/B...

開胃涼菜

遠古時代

先上幾道涼菜,給你們開開胃。所謂的涼菜就是介紹一下python snack的基礎組件,基礎組件不少,相似html,主要有:python

  • Textbox
  • TextboxReflowed
  • Button
  • Compactbutton
  • Checkbox
  • Listbox
  • SingleRadioButton
  • Scale
  • Entry

而後就是一些組合組件,也就是基於上述基礎組件封裝而獲得,主要有:linux

  • RadioBar
  • ButtonBar
  • CheckboxTree

上面這些組件就是全部的基礎組件(組合組件也算基礎組件),這些組件最終呈現還須要gridform這兩個組件,grid表示「網格」的意思,跟html中的table相似,由行和列組成,咱們的基礎組件須要放在網格中來實現頁面佈局;而form也相似「表單」,咱們須要把grid填充到form中,運行後,就能夠看到圖形化頁面了。git

工業革命

通過上面基礎組件的介紹,想必你對snack的組件有了充分的瞭解,這時候你能夠參考文末的refer作幾個小demo,作了以後你會發現頁面是出來了,emmm... 但是感受好繁瑣哦,不少重複性的代碼,並且頁面佈局也怪怪的,若是要把佈局搞好,又須要加不少代碼。github

咱們把用基礎組件的階段稱之爲「遠古時代」,每作一個window,都得一瓦一磚地慢慢堆砌,這樣效率過低了,因此咱們急需一波「工業革命」來提升生產力。數組

python snack彷佛考慮到了這個問題,它在上述基礎組件以外還提供了dialog相關組件,dialog組件即集大成者,一個dialog組件就是一個window,也就是咱們上面所說的form,而且該form中填充了必需的各類基礎組件,dialog組件主要有:iview

  • ListboxChoiceWindow
  • ButtonChoiceWindow
  • EntryWindow

返璞歸真

當今社會,你們吃慣了大魚大肉,反而更是想念農村的野味。同理,咱們用慣了「工業革命」的產物,發現雖然可用,可是僅僅停留在基礎可用級別上,想換換樣式,加加本身的定製化需求,都是有限的,徹底達不到新需求的技術實現要求。因此,咱們不能只知道用別人實現的現成的產物,咱們能夠嘗試着「返璞歸真」一下,迴歸最初的「遠古時代」,本身實現一把「工業革命」。所謂的「dialog」組件無非也就是基礎組件的封裝而已,咱們也能夠本身實現一套本身的組件庫,這個在前端是很是流行的,例如font-awesomeiviewant-design等等。這裏咱們本身實現瞭如下dialog工具

  • ExtButtonChoiceWindow
  • ExtAlert
  • ExtCheckboxWindow
  • ExtListboxChoiceWindow
  • ExtEntryWindow
  • ExtPwdEntryWindow
  • ExtProgressWindow
  • ExtTextWindow

擴展的功能主要有:

  • 熱鍵支持擴展
  • 按鈕樣式擴展
  • 佈局大小自動化擴展
  • 暗文輸入框擴展
  • 彈出窗口擴展
  • 進度條窗口信息展現擴展
  • 動態展現擴展
擴展組件庫地址: widget extend library

管飽正菜

涼菜不夠,正菜來湊。上面就是把python snackAPI羅列了一下,作個小Demo還行,可是距離產品化還很遠,接下來我結合我作部署控制檯工具的實踐經歷分享一下幾個「正菜」,必須夠硬,不接受反駁,不接受批評, O(∩_∩)O ~

熱鍵

python snack提供了兩種幫助用戶使用的途徑,一種是窗口下方的操做提示欄,另外一個就是熱鍵了。熱鍵就是快捷鍵,好比咱們能夠敲擊鍵盤上面的ESC鍵實現頁面的返回。咱們能夠經過調用gridrunOnce接口獲取熱鍵的輸入,例如hotkey = g.runOnce(),而後咱們根據hotkey的值進行判斷並執行對應的操做。

頁面切換

當咱們存在多個頁面的時候,咱們須要頁面切換的功能,翻閱文檔,並無發現提供相似的功能。在咱們的工具中,頁面切換主要有兩種方式,一種是點擊button,一種是熱鍵,既然沒有原生的頁面切換接口,咱們就根據觸發方式手動切換頁面。好比咱們想實現頁面1點擊next按鈕想跳轉頁面2,那咱們只須要獲取button的返回值,判斷是否爲next,若是是next,直接調用頁面2的方法便可,熱鍵同理,即判斷熱鍵內容是否爲對應熱鍵。

ret, button, lb = ExtListboxChoiceWindow(                                  screen, 
    'Distribute Storage Config',
    'Distribute Storage Config',
    ips,
    buttons=("prev", "next", "exit"),
    width=50,
    height=5,
)                                                                                                                                        
if button == "exit" or ret == "ESC":
    screen.finish()
elif button == "prev":
    Welcome_Deploy_Window()
elif button == "next":
    Additional_Config_Window()
elif lb is not None:
    Basic_Host_Window(lb)

增刪改查

增刪改查永遠是一個軟件系統繞不開的基礎功能。

「查」:

首先是總體查看,咱們能夠經過一個列表展現全部信息,這時候咱們能夠用ExtListboxChoiceWindow組件來實現;而後就是單個查看了,咱們可能有多條信息,咱們想查看單個信息的詳細內容時,咱們能夠經過點擊具體的item進入詳細信息的dialog,如何實現呢?listbox中有一個current的概念,也就是listbox中每一個li的惟一標識,咱們能夠用列表的index來填充,由於每每列表頁面的信息也無非是數組或者是列表的方式,咱們獲取到當前的current,即獲取到數組的索引,而後就是根據索引查值了,咱們再調用新增頁面,將查到的值賦值到Textbox便可,Textbox有一個setText就是作這個事情的。固然咱們的ExtEntryWindow組件也能夠作到賦值填充。請參考上述代碼中的lb,其實就是listboxli.current()接口。

「增」:

咱們能夠經過一個新增按鈕或者listbox中的一個li做爲新增按鈕來觸發新增操做,點擊後出現一個dialogdialog中有一些TextboxRadioCheckbox等。

def Basic_Host_Window(current, data=None):
    buttons = [ 'save', 'cancel', 'exit']
    if not data:
        data = ['IP Address:', 'Hostname:', 'Password:']
        if current != 'add':
            data = get_format_data(Basic_Config[current], BASIC_TYPE)
            buttons.insert(1, 'Delete')

    host = ExtEntryWindow(
        screen,
        '{} host'.format('Add' if current == 'add' else 'Edit'),
        'Please fill storage host info.',
        data,
        width = 40, 
        entryWidth = 40, 
        buttons = buttons
    )

「改」:

修改操做的方法是在list頁面選中須要修改的項,而後進入詳情頁面,能夠查看以前建立時填寫的信息,也就是咱們在「查」中查看單個信息提到的方式,咱們所要作的就是在用戶點擊save按鈕的時候,獲取用戶編輯後的數據,再進行一次修改便可,在咱們工具中,此操做就是根據索引修改數組中對應索引的數據而已。

「刪」:

有增就有刪,這邊我暫時還沒實現批量刪除的功能,一方面python snack的支持功能有限,一方面時間有限,因此我只實現了單個刪除的功能,在新增和編輯的頁面添加一個delete按鈕便可,爲了提醒用戶錯刪,咱們還要加上一個確認提示框。

if host[1] == "delete":
    button = ExtButtonChoiceWindow(                                            screen,
        'Delete host',
        'Are you sure to delete current host?'
    )
    if button == "ok":
        del(Basic_Config[current])
    else:
        Basic_Host_Window(current)

組件擴展

構建本身的組件庫真的頗有必要,對於默認的button樣式,我真是吐槽到不想再吐槽,它竟然還認爲本身的bordernice?!因此最終構建本身的組件庫的初衷就是想把各個dialog中的button改成compactbutton,沒辦法,默認的dialog組件不給改呀,因此咱們得本身返璞歸真一下。

固然咱們作擴展組件庫,也不是僅僅由於一個button樣式,還有不少新需求都要依賴本身擴展的組件。好比熱鍵,原生dialog沒法支持熱鍵;還有進度條的進度時間和任務信息展現;還有Gridform的動態佈局等等。具體就不一一介紹了,想深刻了解的直接看代碼,作個小Demo,一目瞭然。

爽口甜菜

充實的正菜吃飽了,是時候來一波甜菜漱漱口,解解渴了。

在作進度條頁面的時候,想除了顯示進度任務完成信息以外,還想顯示一下開始時間和花費時間。發現pythontime模塊比較坑爹,對於時間差的轉換支持不行,查閱資料只發現datetime能夠將時間差轉換爲微秒、秒和小時三個單位,可是我想實現時間差的自動轉換,也就是60s自動轉換爲1min60min轉爲1h24h轉爲1d,超越天爲單位的我就不進行轉換了,邏輯不難,只是拿出來分享給有須要的人,沒必要重複造輪子罷了。

def get_time_interval(start_time):
    start_time = datetime.fromtimestamp(start_time)
    now_time = datetime.fromtimestamp(time.time())
    interval = (now_time - start_time).seconds
    format_interval = get_format_interval(interval)                                                                                          
    return format_interval


def get_format_interval(interval):
    if interval < 60:
        format_interval = "{}s".format(str(interval))
    elif 60 <= interval < 60*60:
        format_interval = "{}min {}s".format(
            str(interval/60), str(interval%60))
    elif 60*60 <= interval < 60*60*24:
        format_interval = "{}h {}min {}s".format(
            str(interval/(60*60)),
            str(interval%(60*60)/60),
            str(interval%(60*60)%60)
        )
    elif 60*60*24 <= interval:
        format_interval = "{}d {}h {}min {}s".format( 
            str(interval/(60*60*24)),
            str(interval%(60*60*24)/60*60),
            str(interval%(60*60)/60),
            str(interval%(60*60)%60)
        )
        
    return format_interval

用餐總結

本來只是想作一個終端圖形化的進度條頁面,可是後續需求愈來愈多,致使作成了一個部署控制檯工具,整個工程開發和優化花了大約兩個星期的時間,項目中遇到的不少難點和問題不少都與python snack無關,因此沒有作詳細解釋,就好比上述的甜菜,你們有興趣的自行翻閱代碼便可。

python snack還有不少未知的我沒有使用,好比checkbox tree等,但我相信萬變不離其宗,有了此次實踐,其餘組件的使用和擴展應該不會花不少時間,其實作這個東西,我最深的感觸就是前端發展的迅速,python snack2000年初的產物了,不少頁面邏輯跟jQuery比起來要弱的多,更別說如今的angularvue等等了,可是領域不一樣,畢竟是僞終端頁面,能作成這樣已經不錯了。若是是真正的桌面圖形化界面(GUI),有pyqt這種神器,功能貌似很強大。

我在以前的一個項目中,就使用過python snack作的控制檯,固然當時不知道是用這個技術作的,當時以爲蠻牛的,嘗試過修改終端文字成漢子,後來沒有成功,便不了了之。此次機緣巧合,工做須要作這麼一個控制檯,在工做中學習和使用本身感興趣的技術的感受真是爽呀。工做中運用技術和本身業餘時間學習新技術並作個小Demo徹底是不同的,工做中運用會不斷有新需求,不斷精益求精,不斷深刻。因此以工做做爲平臺,實現本身的技術價值,會有很大的成就感,與你們共勉咯。(#^.^#)

相關文章
相關標籤/搜索