Julia 內(nèi)置了一個包管理系統(tǒng),可以用這個系統(tǒng)來完成包的管理,當然,你也可以用你的操作系統(tǒng)自帶的,或者從源碼編譯。
你可以在 http://pkg.julialang.org 找到所有已注冊(一種發(fā)布包的機制)的包的列表。
所有的包管理命令都包含在 Pkg
這個 module 里面,Julia 的 Base install 引入了 Pkg
。
可以通過 Pkg.status()
這個方程,打印出一個你所有安裝的包的總結。
剛開始的時候,你沒有安裝任何包::
julia> Pkg.status()
INFO: Initializing package repository /Users/stefan/.julia/v0.3
INFO: Cloning METADATA from git://github.com/JuliaLang/METADATA.jl
No packages installed.
當你第一次運行 Pkg
的一個命令時, 你的包目錄(所有的包被安裝在一個統(tǒng)一的目錄下)會自動被初始化,因為 Pkg
希望有這樣一個目錄,這個目錄的信息被包含于 Pkg.status()
中。
這里是一個簡單的,已經(jīng)有少量被安裝的包的例子:
julia> Pkg.status()
Required packages:
- Distributions 0.2.8
- UTF16 0.2.0
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.6
這些包,都是已注冊了的版本,并且通過 Pkg
管理。
安裝了的包可以是一個更復雜的"狀態(tài)",通過"注釋"來表明正確的版本;當我們遇到這些“狀態(tài)”和“注釋”時我們會解釋的。
為了編程需要,Pkg.installed()
返回一個字典,這個字典對應了安裝了的包的名字和其現(xiàn)在使用的版本:
julia> Pkg.installed()
["Distributions"=>v"0.2.8","Stats"=>v"0.2.6","UTF16"=>v"0.2.0","NumericExtensions"=>v"0.2.17"]
Julia 的包管理有一點不同這是因為它是生命而不是必要。這意味著你告訴它你想要什么,它就會知道安裝什么版本(或移除)來有選擇地滿足那些需求 - 最低程度下地。所以不是安裝一個包,你只是添加它到需求列表然后“解決”什么需要被安裝。特別的,這意味著如果一些包因為它被你想要東西的前一個版本所需要而已經(jīng)被安裝,而且一個更新的版本不再有那個需求了,更新將真正移除那個包。
你的包需求在文件 ~/.julia/v0.3/REQUIRE
中。你可以手動編輯這個文件,然后調(diào)用 Pkg.resolve()
方法來安裝,升級或者移除包來有選擇地滿足需求,或者你可以做 Pkg.edit()
,它將在你的編輯器中打開 REQUIRE
(通過 EDITOR
或者 VISUAL
環(huán)境變量配置),然后之后自動調(diào)用 Pkg.resolve()
,如果有必要的話。如果你僅僅想要添加或者移除一個單一包的需求,你也可以使用非交互的 Pkg.add
和 Pkg.rm
命令,它添加或移除一個單一的需求來 REQUIRE
,然后調(diào)用 Pkg.resolve()
。
你可以用 Pkg.add
函數(shù)添加一個包到需求列表,這個包和所有它所依賴的包都將被安裝:
julia> Pkg.status()
No packages installed.
julia> Pkg.add("Distributions")
INFO: Cloning cache of Distributions from git://github.com/JuliaStats/Distributions.jl.git
INFO: Cloning cache of NumericExtensions from git://github.com/lindahua/NumericExtensions.jl.git
INFO: Cloning cache of Stats from git://github.com/JuliaStats/Stats.jl.git
INFO: Installing Distributions v0.2.7
INFO: Installing NumericExtensions v0.2.17
INFO: Installing Stats v0.2.6
INFO: REQUIRE updated.
julia> Pkg.status()
Required packages:
- Distributions 0.2.7
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.6
這所做的事情首先是添加 Distributions
到你的 ~/.julia/v0.3/REQUIRE
文件:
$ cat ~/.julia/v0.3/REQUIRE
Distributions
然后它使用這些新的需求運行 Pkg.resolve()
,它導向了 Distributions
包應該被安裝因為它是必需的而且沒有被安裝的結論。正如之前所聲明的,你可以通過手動編輯你的 ~/.julia/v0.3/REQUIRE
文件完成相同的事情然后自己運行 Pkg.resolve()
。
$ echo UTF16 >> ~/.julia/v0.3/REQUIRE
julia> Pkg.resolve()
INFO: Cloning cache of UTF16 from git://github.com/nolta/UTF16.jl.git
INFO: Installing UTF16 v0.2.0
julia> Pkg.status()
Required packages:
- Distributions 0.2.7
- UTF16 0.2.0
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.6
這和調(diào)用 Pkg.add("UTF16")
功能相同,除了 Pkg.add
直到在安裝完成之后才改變 REQUIRE
,所以如果有問題的話,REQUIRE
將被剩下,正如在調(diào)用 Pkg.add
之前。REQUIRE
文件的格式在 Requirements Specification中被描述;它允許在其他事物中獲得特定包版本的范圍。
當你決定你不想再擁有一個包,你可以使用 Pkg.rm
來從 REQUIRE
文件移除它的需求:
julia> Pkg.rm("Distributions")
INFO: Removing Distributions v0.2.7
INFO: Removing Stats v0.2.6
INFO: Removing NumericExtensions v0.2.17
INFO: REQUIRE updated.
julia> Pkg.status()
Required packages:
- UTF16 0.2.0
julia> Pkg.rm("UTF16")
INFO: Removing UTF16 v0.2.0
INFO: REQUIRE updated.
julia> Pkg.status()
No packages installed.
再一次,這和編輯 REQUIRE
文件來移除有著包名的那一行然后運行 Pkg.resolve()
來更改安裝包的集合來匹配相類似。盡管 Pkg.add
和 Pkg.rm
對于添加和移除單個包的需求來說是方便的,當你想要添加或移除多個包時,你可以調(diào)用 Pkg.edit()
來手動地改變 REQUIRE
的內(nèi)容然后根據(jù)情況更新你的包。Pkg.edit()
不回滾 REQUIRE
的內(nèi)容如果 Pkg.resolve()
失效 - 不如說,你不得不再一次運行 Pkg.edit()
來修改文檔內(nèi)容。
因為包管理內(nèi)部使用 git 來管理包 git 倉庫,當運行 Pkg.add
時,用戶可能會碰上協(xié)議的問題(比如在一個防火墻后)。接下來的命令可在命令行中被運行來告訴 git 當克隆倉庫時使用 'https' 而不是 'git' 協(xié)議。
git config --global url."https://".insteadOf git://
Julia 包僅僅是 git 倉庫,在任何 git 支持的協(xié)議上都是可克隆的,而且包含遵循特定布局慣例的 Julia 代碼。官方的 Julia 包在 METADATA.jl 倉庫中注冊,在可以著名的地方可獲得。在之前的段落中,Pkg.add
和 Pkg.rm
命令和注冊的包交互,但是包管理也能安裝并使用未注冊的包。為了安裝未注冊的包,使用 Pkg.clone(url)
,在那里 url
是一個包能被克隆的 git URL:
julia> Pkg.clone("git://example.com/path/to/Package.jl.git")
INFO: Cloning Package from git://example.com/path/to/Package.jl.git
Cloning into 'Package'...
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 22 (delta 8), reused 22 (delta 8)
Receiving objects: 100% (22/22), 2.64 KiB, done.
Resolving deltas: 100% (8/8), done.
按照慣例,Julia 倉庫用一個 .jl
的結尾命名(附加的 .git
指示了一個“裸” git 倉庫),這防止它們和其他語言的倉庫碰撞,也使得 Julia 包在搜索引擎中方便找到。當包在你的 .julia/v0.3
目錄下安裝時,然而,擴展是多余的,所以我們將它留下。
如果未注冊的包在它們的資源樹的頂部包含 REQUIRE
文件,那這個文件將被用來決定未注冊的包依賴于哪些注冊的包,而且它們將自動被安裝。未注冊的包和注冊的包一樣,具有相同版本的解決邏輯,所以安裝過的包版本將在必要時調(diào)整來滿足注冊過的和未注冊過的包的需求。
[1] 官方的包集在 https://github.com/JuliaLang/METADATA.jl,但是個人和組織能簡單地使用一個不同的元數(shù)據(jù)倉庫。這允許包可以自動安裝的控制。我們可以僅允許審計通過的和批準的包版本,并使得私人的包和 fork 可被獲得。
當包開發(fā)者發(fā)布你正在使用的新的注冊的包版本時,你當然,想要新的版本。為了獲得最新和最棒的包版本,只要 Pkg.update()
:
julia> Pkg.update()
INFO: Updating METADATA...
INFO: Computing changes...
INFO: Upgrading Distributions: v0.2.8 => v0.2.10
INFO: Upgrading Stats: v0.2.7 => v0.2.8
更新包的第一步是將新的改變放入 ~/.julia/v0.3/METADATA
并看看是否有新的注冊包版本已經(jīng)被發(fā)布了。在這之后,Pkg.update()
通過從包的上游庫 pull 一些更改會更新在一個分支上被檢查且不 dirty(比如,在 git 下沒有對文件更改)的更新包。上游的改變僅僅在如果沒有合并或重定基地址是有必要的情況下應用 - 比如,如果分支是 "fast-forwarded"。如果分支不是 fast-forwarded,就假設你正在使用它而且將自己更改倉庫。
最后,更新的過程重新計算了一個最佳的包版本的集合來安裝以滿足你頂級的需求和 “fix” 包的需求。包被認為是 fixed 如果它是下面幾條之一:
1.未注冊:包不在 METADATA
中 - 你用 Pkg.clone
安裝過它。
2.被檢出:包倉庫在一個開發(fā)分支上。
3.Dirty:在倉庫中對文件進行過了修改。
如果這些中的任何一項出現(xiàn),包管理者不能自由地更改安裝好的包版本,所以它的需求必須被滿足,無論它所選擇的其他包版本是怎樣的。在 ~/.julia/v0.3/REQUIRE
中的頂層需求的組合和修改過的包的需求被用來決定應該安裝什么。
你可能想要使用包的 master
版本而不是注冊版本中的一個。在 master 上可能有修改或功能,它們是你所需要的且沒有在任何注冊版本上發(fā)布,或者你可能是一個包的開發(fā)者且想要改變 master
或一些其他的開發(fā)分支。在這些例子中,你能通過 Pkg.checkout(pkg)
來檢查 pkg
或 Pkg.checkout(pkg,branch)
的 master
分支以檢查一些其他的分支:
julia> Pkg.add("Distributions")
INFO: Installing Distributions v0.2.9
INFO: Installing NumericExtensions v0.2.17
INFO: Installing Stats v0.2.7
INFO: REQUIRE updated.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
julia> Pkg.checkout("Distributions")
INFO: Checking out Distributions master...
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9+ master
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
一旦在用 Pkg.add
安裝 Distributions
之后,在寫完的同時它就位于最新的注冊版本上 - 0.2.9
。然后在運行 Pkg.checkout("Distributions")
之后,你可以從 Pkg.status()
的輸出中看到 Distributions
比起 0.2.9
在一個未注冊的版本上更佳。由 “pseudo-version” 數(shù)字 0.2.9+
指示。
當你檢查一個未注冊的包版本時,包倉庫中 REQUIRE
文件的副本地位高于任何其他在 METADATA
中注冊的需求,所以開發(fā)者保持這個文件的正確性和及時性是很重要的,這反映了目前包版本的真正需求。如果在包倉庫中的 REQUIRE
文件是不正確的或者遺失了,當包被檢出時依賴性可能會被移除。這個文件也被用來填充新發(fā)布的包版本,如果你使用了 Pkg
為此提供的 API(在下面描述)。
當你決定你不再想要讓一個包在分支上被檢出,你能使用 Pkg
“釋放”它回到包管理者的控制之下。
julia> Pkg.free("Distributions")
INFO: Freeing Distributions...
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
在這之后,因為包是在一個注冊版本之上而且不在一個分支上,它的版本將被更新作為包的注冊版本被發(fā)布。
如果你想要在一個指定的版本上 pin 一個包以使調(diào)用 Pkg.update()
不會改變包所在的版本,你可以使用 Pkg.pin
功能:
julia> Pkg.pin("Stats")
INFO: Creating Stats branch pinned.47c198b1.tmp
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7 pinned.47c198b1.tmp
在這之后,Stats
包將以版本 0.2.7
保持 pin 的狀態(tài) - 或者更具體地說,在提交 47c198b1
時,但是自從版本被永久地和一個給定的 git hash 連接后,這就一樣了。Pkg.pin
通過為你想要 pin 包的提交創(chuàng)建一個 throw-away 分支而運行。默認下,它在當前的提交下 pin 了一個包,但是你能通過傳遞第二個參數(shù)選擇一個不同的版本:
julia> Pkg.pin("Stats",v"0.2.5")
INFO: Creating Stats branch pinned.1fd0983b.tmp
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.5 pinned.1fd0983b.tmp
現(xiàn)在 Stats
包在提交 1fd0983b
時被 pin 了,它和 0.2.5
版本相一致。當你決定 “unpin” 一個包且讓包管理者再一次更新它時,你可以使用 Pkg.free
就像你想要離開任何分支一樣:
julia> Pkg.free("Stats")
INFO: Freeing Stats...
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
Julia 的包管理者被設計以讓當你有一個包需要安裝時,你就可以查看它的源代碼和完整的開發(fā)歷史。你也可以對包做出更改,使用 git 提交它們,并能簡單地作出修改和增強。相類似的,系統(tǒng)被設計以讓如果你想要創(chuàng)建一個新的包,這么做最簡單的方法就是在由包管理者提供的基礎設施內(nèi)部。
[2]:不在分支上的包也將被標記為 dirty,如果你在倉庫中作出改變,但是那是一件比較少見的事。
更多建議: