diff options
Diffstat (limited to 'src/luarocks/pack.tl')
-rw-r--r-- | src/luarocks/pack.tl | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/luarocks/pack.tl b/src/luarocks/pack.tl new file mode 100644 index 00000000..8bb284f7 --- /dev/null +++ b/src/luarocks/pack.tl | |||
@@ -0,0 +1,188 @@ | |||
1 | |||
2 | -- Create rock files, packing sources or binaries. | ||
3 | local record pack | ||
4 | end | ||
5 | |||
6 | local queries = require("luarocks.queries") | ||
7 | local path = require("luarocks.path") | ||
8 | local repos = require("luarocks.repos") | ||
9 | local fetch = require("luarocks.fetch") | ||
10 | local fs = require("luarocks.fs") | ||
11 | local cfg = require("luarocks.core.cfg") | ||
12 | local util = require("luarocks.util") | ||
13 | local dir = require("luarocks.dir") | ||
14 | local manif = require("luarocks.manif") | ||
15 | local search = require("luarocks.search") | ||
16 | local signing = require("luarocks.signing") | ||
17 | |||
18 | local type Tree = require("luarocks.core.types.tree").Tree | ||
19 | |||
20 | local type Query = require("luarocks.core.types.query").Query | ||
21 | |||
22 | local type Entry = require("luarocks.core.types.rockmanifest").RockManifest.Entry | ||
23 | |||
24 | --- Create a source rock. | ||
25 | -- Packages a rockspec and its required source files in a rock | ||
26 | -- file with the .src.rock extension, which can later be built and | ||
27 | -- installed with the "build" command. | ||
28 | -- @param rockspec_file string: An URL or pathname for a rockspec file. | ||
29 | -- @return string or (nil, string): The filename of the resulting | ||
30 | -- .src.rock file; or nil and an error message. | ||
31 | function pack.pack_source_rock(rockspec_file: string): string, string | ||
32 | |||
33 | local rockspec, errload = fetch.load_rockspec(rockspec_file) | ||
34 | if errload then | ||
35 | return nil, "Error loading rockspec: "..errload | ||
36 | end | ||
37 | rockspec_file = rockspec.local_abs_filename | ||
38 | |||
39 | local name_version = rockspec.name .. "-" .. rockspec.version | ||
40 | local rock_file = fs.absolute_name(name_version .. ".src.rock") | ||
41 | |||
42 | local temp_dir, err = fs.make_temp_dir("pack-"..name_version) | ||
43 | if not temp_dir then | ||
44 | return nil, "Failed creating temporary directory: "..err | ||
45 | end | ||
46 | util.schedule_function(fs.delete, temp_dir) | ||
47 | |||
48 | local source_file, source_dir = fetch.fetch_sources(rockspec, true, temp_dir) | ||
49 | if not source_file then | ||
50 | return nil, source_dir | ||
51 | end | ||
52 | local ok, errchange = fs.change_dir(source_dir) | ||
53 | if not ok then return nil, errchange end | ||
54 | |||
55 | fs.delete(rock_file) | ||
56 | fs.copy(rockspec_file, source_dir, "read") | ||
57 | ok, err = fs.zip(rock_file, dir.base_name(rockspec_file), dir.base_name(source_file)) | ||
58 | if not ok then | ||
59 | return nil, "Failed packing "..rock_file.." - "..err | ||
60 | end | ||
61 | fs.pop_dir() | ||
62 | |||
63 | return rock_file | ||
64 | end | ||
65 | |||
66 | local function copy_back_files(name: string, version: string, file_tree: {string: any}, deploy_dir: string, pack_dir: string, perms?: string): boolean, string | ||
67 | local ok, err = fs.make_dir(pack_dir) | ||
68 | if not ok then return nil, err end | ||
69 | for file, sub in pairs(file_tree) do | ||
70 | local source = dir.path(deploy_dir, file) | ||
71 | local target = dir.path(pack_dir, file) | ||
72 | if sub is {string: any} then | ||
73 | ok, err = copy_back_files(name, version, sub, source, target) | ||
74 | if not ok then return nil, err end | ||
75 | else | ||
76 | local versioned = path.versioned_name(source, deploy_dir, name, version) | ||
77 | if fs.exists(versioned) then | ||
78 | fs.copy(versioned, target, perms) | ||
79 | else | ||
80 | fs.copy(source, target, perms) | ||
81 | end | ||
82 | end | ||
83 | end | ||
84 | return true | ||
85 | end | ||
86 | |||
87 | -- @param name string: Name of package to pack. | ||
88 | -- @param version string or nil: A version number may also be passed. | ||
89 | -- @param tree string or nil: An optional tree to pick the package from. | ||
90 | -- @return string or (nil, string): The filename of the resulting | ||
91 | -- .src.rock file; or nil and an error message. | ||
92 | function pack.pack_installed_rock(query: Query, tree: string | Tree): string, string | ||
93 | |||
94 | local name, version, repo, repo_url = search.pick_installed_rock(query, tree) | ||
95 | if not name then | ||
96 | return nil, version | ||
97 | end | ||
98 | |||
99 | local root = path.root_from_rocks_dir(repo_url) | ||
100 | local prefix = path.install_dir(name, version, root) | ||
101 | if not fs.exists(prefix) then | ||
102 | return nil, "'"..name.." "..version.."' does not seem to be an installed rock." | ||
103 | end | ||
104 | |||
105 | local rock_manifest, err = manif.load_rock_manifest(name, version, root) | ||
106 | if not rock_manifest then return nil, err end | ||
107 | |||
108 | local name_version = name .. "-" .. version | ||
109 | local rock_file = fs.absolute_name(name_version .. "."..cfg.arch..".rock") | ||
110 | |||
111 | local temp_dir = fs.make_temp_dir("pack") | ||
112 | fs.copy_contents(prefix, temp_dir) | ||
113 | |||
114 | local is_binary = false | ||
115 | if rock_manifest.lib then | ||
116 | local ok, err = copy_back_files(name, version, (rock_manifest.lib as {string: Entry}), path.deploy_lib_dir(repo), dir.path(temp_dir, "lib"), "exec") | ||
117 | if not ok then return nil, "Failed copying back files: " .. err end | ||
118 | is_binary = true | ||
119 | end | ||
120 | if rock_manifest.lua then | ||
121 | local ok, err = copy_back_files(name, version, (rock_manifest.lua as {string: Entry}), path.deploy_lua_dir(repo), dir.path(temp_dir, "lua"), "read") | ||
122 | if not ok then return nil, "Failed copying back files: " .. err end | ||
123 | end | ||
124 | |||
125 | local ok, err = fs.change_dir(temp_dir) | ||
126 | if not ok then return nil, err end | ||
127 | if not is_binary and not repos.has_binaries(name, version) then | ||
128 | rock_file = rock_file:gsub("%."..cfg.arch:gsub("%-","%%-").."%.", ".all.") | ||
129 | end | ||
130 | fs.delete(rock_file) | ||
131 | ok, err = fs.zip(rock_file, table.unpack(fs.list_dir())) | ||
132 | if not ok then | ||
133 | return nil, "Failed packing " .. rock_file .. " - " .. err | ||
134 | end | ||
135 | fs.pop_dir() | ||
136 | fs.delete(temp_dir) | ||
137 | return rock_file | ||
138 | end | ||
139 | |||
140 | function pack.report_and_sign_local_file(file: string, err: string, sign: boolean): boolean, string | ||
141 | if err then | ||
142 | return nil, err | ||
143 | end | ||
144 | local sigfile: string | ||
145 | if sign then | ||
146 | sigfile, err = signing.sign_file(file) | ||
147 | util.printout() | ||
148 | end | ||
149 | util.printout("Packed: "..file) | ||
150 | if sigfile then | ||
151 | util.printout("Signature stored in: "..sigfile) | ||
152 | end | ||
153 | if err then | ||
154 | return nil, err | ||
155 | end | ||
156 | return true | ||
157 | end | ||
158 | |||
159 | function pack.pack_binary_rock(name: string, namespace: string, version: string, sign: boolean, cmd: function(): (string, string)): boolean, string | ||
160 | |||
161 | -- The --pack-binary-rock option for "luarocks build" basically performs | ||
162 | -- "luarocks build" on a temporary tree and then "luarocks pack". The | ||
163 | -- alternative would require refactoring parts of luarocks.build and | ||
164 | -- luarocks.pack, which would save a few file operations: the idea would be | ||
165 | -- to shave off the final deploy steps from the build phase and the initial | ||
166 | -- collect steps from the pack phase. | ||
167 | |||
168 | local temp_dir, err = fs.make_temp_dir("luarocks-build-pack-"..dir.base_name(name)) | ||
169 | if not temp_dir then | ||
170 | return nil, "Failed creating temporary directory: "..err | ||
171 | end | ||
172 | util.schedule_function(fs.delete, temp_dir) | ||
173 | |||
174 | path.use_tree(temp_dir) | ||
175 | local ok, err = cmd() | ||
176 | if not ok then | ||
177 | return nil, err | ||
178 | end | ||
179 | local rname, rversion = path.parse_name(name) | ||
180 | if not rname then | ||
181 | rname, rversion = name, version | ||
182 | end | ||
183 | local query = queries.new(rname, namespace, rversion) | ||
184 | local file, err = pack.pack_installed_rock(query, temp_dir) | ||
185 | return pack.report_and_sign_local_file(file, err, sign) | ||
186 | end | ||
187 | |||
188 | return pack | ||