2023年12月1日 星期五

如何解決在 WSL 安裝 GVM 後,無法使用 "code ." 開啟 VS Code 的問題。

 一、前言

前陣子有鑑於今年都沒有參加什麼 conference,所以就去高雄參加 MOPCON 2023,剛好遇到 Dcard 的工程師,小聊了一下才知道他們目前正在從 Node.js 轉換到 Golang。之前也有跟一些 hunter 小聊,很多開口第一句就是「你會寫 Go(以下皆以此取代 Golang)嗎?」對那時的我來說,這就是「不屬於我的機會」,直到我發現目前靠 C# 在寫後端的我,能夠找的職缺有限(排除金融與博弈),所以就開啟一探 Go 神秘面紗的契機。

二、安裝環境

因為我是個不喜歡在 Windows 開發程式(排除開發 C# 專案,因為會用到 Visual Studio),又想要 Windows 上的服務,所以移除非必要,大部分非 C# 的專案都會在 WSL 上開發。因此就找到保哥寫的如何在 Windows 平台打造完美的 Go 開發環境 (WSL 2),在「安裝 VSCode 需要的 go modules 與相關工具」之前的內容基本上就是再用中文交代過一次 gvm 在 GitHub 上的說明。

不過有一個小地方在 GitHub 有提到,但文章中漏掉了,那就是當你從來沒有安裝過 Go 的任何版本時,如果你要安裝 Go 1.5+ 以上的版本,你需要安裝 Go 1.4,主要原因是因為 Go 1.5+ 把  C compilers 移除了。

三、我遇到什麼問題

常用 VS Code 的人就知道,可以在 cmd 切換到指定 repo 後,透過 "code ." 在當下路徑開啟 VS Code,在 WSL 上只要設定好也是如此。但正當我準備開心的進入 Go 的世界時,我發現我無法開啟我的 VS Code!

從錯誤來看,它不認識 "code" 是什麼意思了?怎麼會這樣?於是我開始做以下檢查

  1. 在 Windows 用 Git Bash 可否使用 "code ." => 可以
  2. 重新安裝 VS Code 的 WSL extension 後,在 WSL 嘗試使用 "code ." => 不可以
  3. 重新安裝 VS Code 後,在 WSL 嘗試使用 "code ." => 不可以
  4. 將 gvm 移除後,在 WSL 嘗試使用 "code ." => 不可以
  5. 將 gvm 安裝後,於 .bashrc 所加入的
    [[ -s "/home/cyli/.gvm/scripts/gvm" ]] && source "/home/cyli/.gvm/scripts/gvm"
    註解掉後,在 WSL 嘗試使用 "code ." => 可以,但變成找不到 Go。

四、深入整個安裝流程

1. gvm-installer

執行了 gvm-installer,然後寫進 bash
bash < <(curl -s -S -L
  https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
寫進去的內容就是我前面提到的內容
GVM_DEST=${2:-$HOME}
GVM_NAME="gvm"
[ "$GVM_DEST" = "$HOME" ] && GVM_NAME=".gvm"
source_line="[[ -s \"${GVM_DEST}/$GVM_NAME/scripts/gvm\" ]] && source \"${GVM_DEST}/$GVM_NAME/scripts/gvm\""
source_file="${GVM_DEST}/$GVM_NAME/scripts/gvm"
if [ -z "$GVM_NO_UPDATE_PROFILE" ] ; then
  if [ -f "$HOME/.zshrc" ]; then
    update_profile "$HOME/.zshrc"
  fi
  if [ "$(uname)" == "Linux" ]; then
    update_profile "$HOME/.bashrc" || update_profile "$HOME/.bash_profile"
  elif [ "$(uname)" == "Darwin" ]; then
    LOGIN_SHELL=$(finger $(id -u -n) | grep Shell | cut -d : -f 3)
    echo "macOS detected. User shell is:" $LOGIN_SHELL
    if [ $LOGIN_SHELL == "/bin/zsh" ]; then # macOS moved to ZSH after macOS Catalina
      pdate_profile "$HOME/.zshrc"
    else
      update_profile "$HOME/.profile" || update_profile "$HOME/.bash_profile"
    fi
  fi
fi

2. .gvm/script/gvm

執行 gvm-default
export GVM_ROOT=/home/cyli/.gvm
. $GVM_ROOT/scripts/gvm-default

3.  $GVM_ROOT/script/gvm-default

重設各種變數,並且修改 PATH,最後執行 $GVM_ROOT/environments/default(如果存在), $GVM_ROOT/scripts/env/gvm 與 $GVM_ROOT/scripts/env/cd
unset GOROOT
unset GOARCH
unset GOOS
unset GOPATH
unset GOBIN

unset gvm_go_name
unset gvm_pkgset_name

mkdir -p "$GVM_ROOT/logs" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/gos" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/archive" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/archive/package" > /dev/null 2>&1
mkdir -p "$GVM_ROOT/environments" > /dev/null 2>&1

export GVM_VERSION=$(cat "$GVM_ROOT/VERSION")
export PATH="$GVM_ROOT/bin:$PATH"
export GVM_PATH_BACKUP="$PATH"
[ -f "$GVM_ROOT/environments/default" ] && . "$GVM_ROOT/environments/default"
. "$GVM_ROOT/scripts/env/gvm"

. "$GVM_ROOT/scripts/env/cd" && cd .

4. $GVM_ROOT/environments/default

重新設定各種環境變數,包含 PATH。

5. $GVM_ROOT/scripts/env/gvm

設定各種指令的路徑

6. $GVM_ROOT/scripts/env/cd

其中有一段耐人尋味
# Path cleanup
#
# Sort all paths, place rvm paths first, followed by gvm, followed by the rest.
# We do this so that rvm and gvm can live together happily.
#
# NOTE: Cleanup will also take place everytime 'gvm use' or 'gvm pkgset use' is
# executed but we do it now just to call it from some place on login.
#
export PATH="$(__gvm_munge_path)"

五、Walkaround

最終,我嘗試在 .bashrc 裡,再次設定 VS Code 的 PATH,結果就解決了。至於會不會有其他跟 VS Code 有一樣的狀況,可能要等之後遇到再說。
不過有個特別的現象是,因為 Windows 裡會有檔案的名稱含有空白,在我的 WSL 會用 ":" 取代,我有嘗試加入一樣的路徑,但結果不行,最後是加入含有跳脫的版本。

六、後記

我有嘗試在保哥的文章底下留言詢問,不過我推測並不會有通知,所以保哥並沒有回應。而我也到了 Go程式語言 (Golang Taiwan, Gopher Taipei) 的 Facebook 社團去求教,不過看起來大家都不太推 gvm,頂多是推 goenv,但我還是覺得可能可以堅持一下,雖然結果也不算有根本解決,不過至少可以讓我舒服開發了。

四、References

2021年7月18日 星期日

JavaScript: Expressions vs. statements

一、前言

為什麼突然想講這個主題呢? 因為在工作上,有大量的時間都在寫 JavaScript,然後從兩個人合作,到三個人合作,現在則是到了四個人合作,但彼此之前卻明有明訂的 coding style。雖然整體來說影響不大,因為大部分時間都是在 GTM(Google Tag Manager) 上編寫,影響範圍有所侷限,但長時間下來的 review 則會造成無形的成本增加。於是,我開始找尋適合的 coding style,卻意外地從 Strict mode 的設定,掉進 IIFE(Immediately Invoked Functions Expressions),然後為了通透的理解 IIFE,所以深入了解 expression 跟 statement 的差別。

二、Expressions

1. 從 MDN 上看定義:

An expression is any valid unit of code that resolves to a value.
var a = 1; // statement
b = 2 ; // expression

2. Arithmetic Expressions:

1 + 1; // return 2

3. String Expressions:

'a' + 'b'; // return "ab"

4. Logical Expressions:

A. Logical AND(&&)

'Cat' && 'Dog'; // return "Dog"
'Cat' && false; // return false
'Dog' && true; // return true

B. Logical OR(||)

'Cat' || 'Dog'; // return "Cat"
'Cat' || false; // return "Cat"
false || 'Dog'; // return "Dog"

C. Logical NOT(!)

!'Cat'; // return false

5. Primary Expressions:

A. this

this.window; // return window

B. delete

const myObj = {a: 1, b: 2};
delete myObj.a; // return true
delete myObj.c; // return true
delete myObj; // return false
delete Math.PI; // return false
myObj2 = {c: 3};
delete myObj2; // return true

C. typeof

typeof 1; // return "number"
typeof 'String'; // return "string"
typeof String; // return "function"
typeof []; // return "object"
typeof {}; // return "object"
typeof true; // return "boolean"
typeof function() {}; // return "function"
typeof Function; // returns "function"
typeof undefined; // return "undefined"
typeof null; // return "object"
typeof NaN; // return "number"
typeof Infinity; // return "number"
typeof Date; // returns "function"
typeof Date(); // return "string"
typeof new Date(); // return "object"
typeof Math; // returns "object"

D. void

1 == '1'; // return true;
void 1 == '1'; // return false
void (1 == '1'); // return undefined

6. Left-hand-side Expressions:

我覺得這部分如果把下面的 assignment expressions 拿來這邊混淆,好像不太好。但我一時間好像也沒有辦法把這邊做比較完整的釐清,所以就暫時留白。

A. new

B. super

7. Assignment Expressions:

b = 2 ; // return 2

三、Statements

1. Control flow:

A. Block

B. break

C. continue

D. Empty

E. if...else

F. switch

G. throw

H. try...catch

2. Declarations:

A. var

B. let

C. const

3. Functions and classes:

A. function

B. function*

C. async function

D. return

E. class

4. Iterations:

A. do...while

B. for

C. for...in

D. for...of

E. for await...of

F. while

5. Others:

A. debugger

B. export

C. import

D. import.meta

E. label

F. with

四、Function Expressions 與 Function Statements

1. Function Statements

function myFun() {
  console.log('Hello my fun.');
}

myFun(); // output: "Hello my fun."

2. Function Expressions

var fac = function me(x) { return x <= 1 ? 1 : x * me(x-1) };
fac(10); // return 32628800
console.log(me); // ReferenceError: me is not defined
var foo = function() {};
foo(); // return undefined

五、其他錯綜複雜的案例

1. Comma operator

a = 1, 2; // return 1
a = (1, 2); // return 2

2. Object 與 block

{}; // return udefined
a = {};
typeof a; // return "object"

function sum(a, b) {
  return a + b;
}
{ foo: sum(1, 2) }; // return 3

b = { foo: sum(1, 2) };
typeof b; // return "object"

3. 神奇的 Unary plus(+)

1 + 'string'; // return "1string"
1 + undefined; // return NaN
1 + null; // return 1
1 + Infinity; // return Infinity
1 + [2, 3]; // return "12,3"
1 + {a: 1}; // return "1[object Object]"
[] + []; // return ""
[] + {}; // return "[object Object]"
{}+[]; // return 0

4. eval

eval("{foo: 123}"); // return 123
eval("({foo: 123})"); // return {foo: 123}

六、如何快速辨別到底是 expression,還是 statement 呢?

拿一個變數來 assign 看看就知道
var a = console.log('a');
a; // return undefined
所以 console.log('a'); 是 expression 還是 statement  呢?

七、後記

在這個查資料的過程,意外發現許多平常不會用到的內容,另外則是有點回憶起以前在大學裡上的「程式語言」與「編譯程式」,讓我有些回歸學生年代的錯覺。

八、References

2021年6月28日 星期一

JavaScript: Event Loop

前言

有天早上醒來,我忽然在想,當我寫了
setTimeout(function() {
  alert('Hello World!');
}, 5 * 1000);
我真的是五秒之後會看到 "Hello World!" 嗎?如果是,那 JavaScript 怎麼可能是 Single Thread。如果不是,他有是怎麼做讓我「以為」我真的是五秒後看到?

JavaScript 怎麼執行

其他把  Philip Roberts 的影片看完,大概就差不多理解了,所以這邊我就不再贅述了。簡單來說,沒錯 JavaScript 是 Single Thread,所以程式就是由上往下執行,但並非每段程式碼都能由 JavaScript 獨立執行,setTimeout 就是其中一個例子。當你執行 setTimeout,時間是五秒,他就會被丟掉 WebAPI 去處理,等時間到了,再回來 task queue 排隊。所以你說,五秒還會是五秒嗎?有可能是,但不能保證是,只能說,最短是五秒。

再舉例,有時會,我們會發一個 GET request,如果網頁要等 response 才能繼續往下執行,就能容易造成 blocking。所以這時候若使用 async,那就像上面的例子,你可以繼續往下執行,而 response 回來,會被丟進 task queue 排隊,等到下一次換他執行再處理。
 
而 Single Thread 也造就了 never blocking 的特性,因為不會有其他 thread 來 interrupt 所以在執行次序上比較好控管,也不會處理 multi-thread 所以需要煩惱的問題。關於 JavaScript 為什麼不用 multi-thread 我之後沒有意外會再寫一篇。

後記

其實我在工作中,有幾次強制讓 GET request sync,因為我一定要拿到資料才能往下做,我下面也沒有其他事情要做了。但其實想想這樣對網頁能呈現上真的可能會有不良的影響的影響,萬一 response 等了很久最後 timeout 了,不就是賠了夫人又折兵。

References

2019年12月14日 星期六

使用 SourceTree 連接 Github,SSH 有那麼難?

前言

接續前面的主題,為了學習 Git,在 Windows下使用 Sourcetree 來提供方便的 GUI。如果是一個人開發,這樣也就夠了。如果想要更方便的分享自己的成果,大概就會想到 GitHub。當然還有很多方式可以分享,不過更重要的一點是,透過 GitHub,可以更方便達到「多人協作」,而不再只是自己閉門造車了。

那就連線吧!

這件事情其實不難,隨便 google 應該的可以找到教學文,例如這個。那這樣我有什麼好講的?我只是想來分享一下自己的愚蠢。

當你生好一組 Public/Private Key 之後,一定會記得,要把 Key 存好,記得 Private Key 不要洩漏出去,不然在沒有數位簽證的情況下,你的行為就可能會被假冒。(有點想講一篇密碼學的文章,但感覺篇幅很長,怕自己駕馭不了。)

好了,接下來就是要在 GitHub 上,把自己的 Public Key 新增進去。然後我就失敗了,為什麼?因為我新增了這個:

這是什麼呢?就是當時生完 Key 之後,存下來的 Public Key。如果把它貼進 GitHub,大概就會得到格式不符的警告。

而正確的格式長怎樣呢?其實就是這樣:

內容上大致一樣,但就是因為這小小的差異,讓我撞牆了。只能說是自己對格式不夠熟悉,所以希望透過自己的經驗,幫助其他人少走冤枉路。另外,其實我引用的文章寫得很完整,如果照他做,也不會碰到我的問題,所以就提供給各位參考了。

References

使用 SourceTree 使用 SSH 連接 Github
https://dotblogs.com.tw/acelee/2019/07/24/164337

2019年11月17日 星期日

在 Windows 使用 Sourcetree 那麼難?

前言

在工作之前,是有上過幾次Git的課程,但是因為怎麼開發都是自己做,而且開發的東西也不大,就沒想真的導入版本控制。再加上沒也參加過什麼社群,GitHub也是空空的,直到之前參加DIGI+ Talent跨域數位人才加速躍升計畫,到資策會數位教育研究所當了半年的研習生,用了Slack溝通,並第一次把自己寫的Code丟上GitHub。

工作後,一切來真的,因為需要共同開發,所以要再重新熟悉一下Git,而在Window介面下,Sourcetree是蠻多人推薦的GUI軟體,在公司也裝這套,所以就想趁下班時間,在自己的筆電也裝上,好讓自己可以更有效的學習,並不要拖累工作進度。

說好的一直下一步呢?

網路上已經有夠多教學,告訴你該怎麼安裝,在這裡就不再多放這些連結,也不多做說明了。照過去的常理其實沒有太多東西要注意,就是該辦會員的辦會員,該按下一步的按下一步,不過怎麼Logo出來轉一轉就消失了?

在Google裡找答案:

1. 把資料夾刪一刪重裝

2. 舊版本有問題,裝新的就好了。

3. 裝舊版的,新版有問題。

4. .NET Framework更新就好了

5. WMI壞掉了

太好了,好像找到問題了

我的WMI好像真的會壞掉了,實際原因我不知道。但是,我的狀況又跟他的不太一樣。當我在CMD下"winmgmt /verifyrepository"沒有不一致的現象,所以他提到的修復模式沒用。後來我是靠修復的,感覺跟原本的問題差很遠了,但是有用。有些可能有幫助的連結我留在下面,希望可以幫助想在 Windows 用 Sourcetree 學 Git 的朋友。

後記

沒想過會搞那麼久,曾經有一度想要放棄,換別套,幸好後來有找到路,並且一步一步解決問題。另外的感想是,這套感覺不是太穩定,因為安裝失敗的例子超多,然後解決方法又一堆。不過不是Open Source的Free Software不能要求太多,能夠使用已經要滿滿的感謝了。

References

Git
https://git-scm.com/

GitHub
https://github.com/

Sourcetree
https://www.sourcetreeapp.com/

WMI: Missing or Failing WMI Providers or Invalid WMI Class

如何在Win10上修复或重建WMI存储库
http://www.microwi10.com/wenzhang/jiaocheng/2019-02-25/13044.html

OPSMGR AGENT INSTALL ERROR 25218
http://www.ms-opsmgr.eu/?p=69

Source Tree failing to install and run
https://community.atlassian.com/t5/Sourcetree-questions/Source-Tree-failing-to-install-and-run/qaq-p/606402

2019年9月27日 星期五

在Blogger嵌入程式碼,使用Google Code Prettify

前言

因為上班之後,要學的東西太多了,主管建議我可以筆記下來,後來我想說乾脆就寫部落格吧!如果要寫技術類的,或多或少也要貼一些範例程式碼。只是沒想到Blogger居然沒有支援,所以只好來找個方式來解決。

其實很簡單

基本設定

我是個懶惰的人,設定太多的不用,後來就選到Google Code Prettify。其實只要參考google/code-prettify裡面做設定就可以完成了:

這段JavaScript需要放進Blooger,放哪裡?隨便。不是啦,放在:

版面配置裡面有辦法新增小工具的地方,有很多?沒關係,隨便找一個地方放,下次再寫一篇討論這個問題。
選擇HTML/JavaScript,之後,把下面那段script丟進去:

<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script>
我的好像長的不一樣,這等一下講。

之後呢,就可以在寫文章時,透過切換成HTML模式,把你想要的程式碼嵌進去了。你可以選擇先在撰寫頁貼上,在切過去修改,或者直接在那邊處理。不過我是建議前者,因為這樣很直覺,也可以省去一些不必要的工(因為如果是用後者,則需要再將程式碼轉換過,避免一些"<" 、">"等被解讀錯誤。而前者則是blogger已顯示為前提轉換成HTML裡的編碼,所以就不用再找工具來轉換。)。再來就是確定程式碼是否有擺對地方了:
要用,<pre></pre>或是<code></code>包起來。
好了,這樣就有基本功能了。接下來:

其他設定

設定語言

顯示行數

設定外觀

你可以透過設定skin來達到更換風格,至於可以填的值要查Gallery of themes for code prettify,但是因為有點不合我胃口,所以我選擇Plan B。COLOR THEMESFORGOOGLE CODE PRETTIFY裡面選擇更多了,而且只要在之前在script的地方前頭貼上CSS,並且用<style></style>包起來就好了,這也就是為什麼上面我的script會比較雜的原因。

後記

即便是一篇不算很難的文章,還是花了很久,寫得不一定很好,也許還是可以考慮一下下方的連結。不過我覺得,至少我不是用抄襲的,希望會慢慢進步。

References

2019年9月20日 星期五

Syntactic sugar

前言

九月終於開始自己第一份正式的全職工作,原本預期會先寫JavaScript,所以職前有再學了一下,結果沒想到一開始是寫自己原本不想碰的C#。倒也不是不喜歡,只是自己原本想學的語言,他的次序比較後面,但是不管,反正學什麼都好,只要能夠變強我都可以。由於語法與過去學習C/C++頗為相似,所以大致上沒有障礙,只是出現一些奇形怪狀的語法,也問了一些奇怪的問題。Google一下,也許應該稱為"Syntactic sugar",或中譯成「語法糖」,太噁心了,還是用英文來稱呼好了。

Syntactic sugar

Sugar,糖,吃糖,有甜頭。也程式有時候是痛苦的,因為有些東西是既定的,寫起來很「ak-tsak」,這時候如果可以簡單一點寫,又不影響功能不就太好了。所以就讓compiler/interpreter 來幫忙處理,在寫程式時就可以爽一點。不過,吃糖一時爽,一直吃糖一直爽?

起源

維基百科有寫到,"Syntactic sugar"是Peter J. Landin 這位先生看人家寫 ALGOL-like programming language時,有很像lambda calculus的寫法,所以就這樣說了。

一些範例

C

// 這在我年輕時可是讓我想破頭
a = a + b;
a += b;

// 雖然指標用的也算習慣,不這樣也算Syntactic sugar?
a[i] == *(a + i);
a->x == (*a).x;

// 這還蠻好用的
int a = b > c ? d : e;

C#

// 由complier自動判斷型別
var x = expr
// 自動呼叫Dispose()釋放資源
using (var sr = new StreamReader(filename))
{

}

對我來說

在沒學之前,會覺得這是什麼糖?可能本來會的知識,被包裹起來不認得了。我記得那時我要用C#寫一支處理CSV的程式,我看CsvHelper官方寫著:
// 由complier自動判斷型別
using (var sr = new StreamReader(filename))
using (var csv = new CsvReader(sr))
{

}
我還跟主管說:「我不知道這個using是要放在哪」,因為C#是用using來接package。知道答案後,真的應該怪當初他出C#的考題,我直接跳過不寫。所以還是要多看多學,才比較有可能知道別人在寫些什麼。最近還有?與??,看別人的程式真的是處處有驚喜。

Derivative terms

Syntactic salt

這就是相反來說,那些對於程式閱讀或撰寫有害的方式。

Syntactic saccharin

這則是指那些華而不實的"Syntactic sugar",簡單來說,炫技、耍花槍。

References

Lambda calculus:
https://en.wikipedia.org/wiki/Lambda_calculus
C#语法糖(Csharp Syntactic sugar)大汇总: