Julia 內(nèi)置了一個(gè)包管理系統(tǒng),可以用這個(gè)系統(tǒng)來完成包的管理,當(dāng)然,你也可以用你的操作系統(tǒng)自帶的,或者從源碼編譯。
你可以在 http://pkg.julialang.org 找到所有已注冊(cè)(一種發(fā)布包的機(jī)制)的包的列表。
所有的包管理命令都包含在 Pkg
這個(gè) module 里面,Julia 的 Base install 引入了 Pkg
。
可以通過 Pkg.status()
這個(gè)方程,打印出一個(gè)你所有安裝的包的總結(jié)。
剛開始的時(shí)候,你沒有安裝任何包::
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.
當(dāng)你第一次運(yùn)行 Pkg
的一個(gè)命令時(shí), 你的包目錄(所有的包被安裝在一個(gè)統(tǒng)一的目錄下)會(huì)自動(dòng)被初始化,因?yàn)?Pkg
希望有這樣一個(gè)目錄,這個(gè)目錄的信息被包含于 Pkg.status()
中。
這里是一個(gè)簡(jiǎn)單的,已經(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
這些包,都是已注冊(cè)了的版本,并且通過 Pkg
管理。
安裝了的包可以是一個(gè)更復(fù)雜的"狀態(tài)",通過"注釋"來表明正確的版本;當(dāng)我們遇到這些“狀態(tài)”和“注釋”時(shí)我們會(huì)解釋的。
為了編程需要,Pkg.installed()
返回一個(gè)字典,這個(gè)字典對(duì)應(yīng)了安裝了的包的名字和其現(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 的包管理有一點(diǎn)不同這是因?yàn)樗巧皇潜匾?。這意味著你告訴它你想要什么,它就會(huì)知道安裝什么版本(或移除)來有選擇地滿足那些需求 - 最低程度下地。所以不是安裝一個(gè)包,你只是添加它到需求列表然后“解決”什么需要被安裝。特別的,這意味著如果一些包因?yàn)樗荒阆胍獤|西的前一個(gè)版本所需要而已經(jīng)被安裝,而且一個(gè)更新的版本不再有那個(gè)需求了,更新將真正移除那個(gè)包。
你的包需求在文件 ~/.julia/v0.3/REQUIRE
中。你可以手動(dòng)編輯這個(gè)文件,然后調(diào)用 Pkg.resolve()
方法來安裝,升級(jí)或者移除包來有選擇地滿足需求,或者你可以做 Pkg.edit()
,它將在你的編輯器中打開 REQUIRE
(通過 EDITOR
或者 VISUAL
環(huán)境變量配置),然后之后自動(dòng)調(diào)用 Pkg.resolve()
,如果有必要的話。如果你僅僅想要添加或者移除一個(gè)單一包的需求,你也可以使用非交互的 Pkg.add
和 Pkg.rm
命令,它添加或移除一個(gè)單一的需求來 REQUIRE
,然后調(diào)用 Pkg.resolve()
。
你可以用 Pkg.add
函數(shù)添加一個(gè)包到需求列表,這個(gè)包和所有它所依賴的包都將被安裝:
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
然后它使用這些新的需求運(yùn)行 Pkg.resolve()
,它導(dǎo)向了 Distributions
包應(yīng)該被安裝因?yàn)樗潜匦璧亩覜]有被安裝的結(jié)論。正如之前所聲明的,你可以通過手動(dòng)編輯你的 ~/.julia/v0.3/REQUIRE
文件完成相同的事情然后自己運(yùn)行 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中被描述;它允許在其他事物中獲得特定包版本的范圍。
當(dāng)你決定你不想再擁有一個(gè)包,你可以使用 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
文件來移除有著包名的那一行然后運(yùn)行 Pkg.resolve()
來更改安裝包的集合來匹配相類似。盡管 Pkg.add
和 Pkg.rm
對(duì)于添加和移除單個(gè)包的需求來說是方便的,當(dāng)你想要添加或移除多個(gè)包時(shí),你可以調(diào)用 Pkg.edit()
來手動(dòng)地改變 REQUIRE
的內(nèi)容然后根據(jù)情況更新你的包。Pkg.edit()
不回滾 REQUIRE
的內(nèi)容如果 Pkg.resolve()
失效 - 不如說,你不得不再一次運(yùn)行 Pkg.edit()
來修改文檔內(nèi)容。
因?yàn)榘芾韮?nèi)部使用 git 來管理包 git 倉庫,當(dāng)運(yùn)行 Pkg.add
時(shí),用戶可能會(huì)碰上協(xié)議的問題(比如在一個(gè)防火墻后)。接下來的命令可在命令行中被運(yùn)行來告訴 git 當(dāng)克隆倉庫時(shí)使用 'https' 而不是 'git' 協(xié)議。
git config --global url."https://".insteadOf git://
Julia 包僅僅是 git 倉庫,在任何 git 支持的協(xié)議上都是可克隆的,而且包含遵循特定布局慣例的 Julia 代碼。官方的 Julia 包在 METADATA.jl 倉庫中注冊(cè),在可以著名的地方可獲得。在之前的段落中,Pkg.add
和 Pkg.rm
命令和注冊(cè)的包交互,但是包管理也能安裝并使用未注冊(cè)的包。為了安裝未注冊(cè)的包,使用 Pkg.clone(url)
,在那里 url
是一個(gè)包能被克隆的 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 倉庫用一個(gè) .jl
的結(jié)尾命名(附加的 .git
指示了一個(gè)“裸” git 倉庫),這防止它們和其他語言的倉庫碰撞,也使得 Julia 包在搜索引擎中方便找到。當(dāng)包在你的 .julia/v0.3
目錄下安裝時(shí),然而,擴(kuò)展是多余的,所以我們將它留下。
如果未注冊(cè)的包在它們的資源樹的頂部包含 REQUIRE
文件,那這個(gè)文件將被用來決定未注冊(cè)的包依賴于哪些注冊(cè)的包,而且它們將自動(dòng)被安裝。未注冊(cè)的包和注冊(cè)的包一樣,具有相同版本的解決邏輯,所以安裝過的包版本將在必要時(shí)調(diào)整來滿足注冊(cè)過的和未注冊(cè)過的包的需求。
[1] 官方的包集在 https://github.com/JuliaLang/METADATA.jl,但是個(gè)人和組織能簡(jiǎn)單地使用一個(gè)不同的元數(shù)據(jù)倉庫。這允許包可以自動(dòng)安裝的控制。我們可以僅允許審計(jì)通過的和批準(zhǔn)的包版本,并使得私人的包和 fork 可被獲得。
當(dāng)包開發(fā)者發(fā)布你正在使用的新的注冊(cè)的包版本時(shí),你當(dāng)然,想要新的版本。為了獲得最新和最棒的包版本,只要 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
并看看是否有新的注冊(cè)包版本已經(jīng)被發(fā)布了。在這之后,Pkg.update()
通過從包的上游庫 pull 一些更改會(huì)更新在一個(gè)分支上被檢查且不 dirty(比如,在 git 下沒有對(duì)文件更改)的更新包。上游的改變僅僅在如果沒有合并或重定基地址是有必要的情況下應(yīng)用 - 比如,如果分支是 "fast-forwarded"。如果分支不是 fast-forwarded,就假設(shè)你正在使用它而且將自己更改倉庫。
最后,更新的過程重新計(jì)算了一個(gè)最佳的包版本的集合來安裝以滿足你頂級(jí)的需求和 “fix” 包的需求。包被認(rèn)為是 fixed 如果它是下面幾條之一:
1.未注冊(cè):包不在 METADATA
中 - 你用 Pkg.clone
安裝過它。
2.被檢出:包倉庫在一個(gè)開發(fā)分支上。
3.Dirty:在倉庫中對(duì)文件進(jìn)行過了修改。
如果這些中的任何一項(xiàng)出現(xiàn),包管理者不能自由地更改安裝好的包版本,所以它的需求必須被滿足,無論它所選擇的其他包版本是怎樣的。在 ~/.julia/v0.3/REQUIRE
中的頂層需求的組合和修改過的包的需求被用來決定應(yīng)該安裝什么。
你可能想要使用包的 master
版本而不是注冊(cè)版本中的一個(gè)。在 master 上可能有修改或功能,它們是你所需要的且沒有在任何注冊(cè)版本上發(fā)布,或者你可能是一個(gè)包的開發(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
之后,在寫完的同時(shí)它就位于最新的注冊(cè)版本上 - 0.2.9
。然后在運(yùn)行 Pkg.checkout("Distributions")
之后,你可以從 Pkg.status()
的輸出中看到 Distributions
比起 0.2.9
在一個(gè)未注冊(cè)的版本上更佳。由 “pseudo-version” 數(shù)字 0.2.9+
指示。
當(dāng)你檢查一個(gè)未注冊(cè)的包版本時(shí),包倉庫中 REQUIRE
文件的副本地位高于任何其他在 METADATA
中注冊(cè)的需求,所以開發(fā)者保持這個(gè)文件的正確性和及時(shí)性是很重要的,這反映了目前包版本的真正需求。如果在包倉庫中的 REQUIRE
文件是不正確的或者遺失了,當(dāng)包被檢出時(shí)依賴性可能會(huì)被移除。這個(gè)文件也被用來填充新發(fā)布的包版本,如果你使用了 Pkg
為此提供的 API(在下面描述)。
當(dāng)你決定你不再想要讓一個(gè)包在分支上被檢出,你能使用 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
在這之后,因?yàn)榘窃谝粋€(gè)注冊(cè)版本之上而且不在一個(gè)分支上,它的版本將被更新作為包的注冊(cè)版本被發(fā)布。
如果你想要在一個(gè)指定的版本上 pin 一個(gè)包以使調(diào)用 Pkg.update()
不會(huì)改變包所在的版本,你可以使用 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
時(shí),但是自從版本被永久地和一個(gè)給定的 git hash 連接后,這就一樣了。Pkg.pin
通過為你想要 pin 包的提交創(chuàng)建一個(gè) throw-away 分支而運(yùn)行。默認(rèn)下,它在當(dāng)前的提交下 pin 了一個(gè)包,但是你能通過傳遞第二個(gè)參數(shù)選擇一個(gè)不同的版本:
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
時(shí)被 pin 了,它和 0.2.5
版本相一致。當(dāng)你決定 “unpin” 一個(gè)包且讓包管理者再一次更新它時(shí),你可以使用 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 的包管理者被設(shè)計(jì)以讓當(dāng)你有一個(gè)包需要安裝時(shí),你就可以查看它的源代碼和完整的開發(fā)歷史。你也可以對(duì)包做出更改,使用 git 提交它們,并能簡(jiǎn)單地作出修改和增強(qiáng)。相類似的,系統(tǒng)被設(shè)計(jì)以讓如果你想要?jiǎng)?chuàng)建一個(gè)新的包,這么做最簡(jiǎn)單的方法就是在由包管理者提供的基礎(chǔ)設(shè)施內(nèi)部。
[2]:不在分支上的包也將被標(biāo)記為 dirty,如果你在倉庫中作出改變,但是那是一件比較少見的事。
更多建議: