@@ -32,6 +32,8 @@ const fs = require('fs-extra');
3232const fg = require ( 'fast-glob' ) ;
3333const path = require ( 'path' ) ;
3434const consola = require ( 'consola' ) ;
35+ const bent = require ( 'bent' ) ;
36+ const tar = require ( 'tar' ) ;
3537const Package = require ( './package.js' ) ;
3638const { getPrefix} = require ( './utils/vfs.js' ) ;
3739const logger = consola . withTag ( 'Packages' ) ;
@@ -42,10 +44,17 @@ const readOrDefault = filename => fs.existsSync(filename)
4244 ? fs . readJsonSync ( filename )
4345 : [ ] ;
4446
47+ const extract = ( stream , target ) => new Promise ( ( resolve , reject ) => {
48+ stream . once ( 'end' , ( ) => resolve ( ) ) ;
49+ stream . once ( 'error' , error => reject ( error ) ) ;
50+ stream . pipe ( tar . extract ( { C : target } ) ) ;
51+ } ) ;
52+
4553/**
4654 * @typedef InstallPackageOptions
55+ * @param {string } root
4756 * @param {boolean } system
48- * @param {object } [auth ]
57+ * @param {object } [headers ]
4958 */
5059
5160/**
@@ -144,9 +153,38 @@ class Packages {
144153 * Installs a package from given url
145154 * @param {string } url
146155 * @param {InstallPackageOptions } options
156+ * @param {object } user
147157 */
148- async installPackage ( url , options ) {
149- throw new Error ( 'Not implemented yet' ) ;
158+ async installPackage ( url , options , user ) {
159+ const { realpath} = this . core . make ( 'osjs/vfs' ) ;
160+
161+ const name = path . basename ( url . split ( '?' ) [ 0 ] )
162+ . replace ( / \. [ ^ / . ] + $ / , '' ) ;
163+
164+ const stream = await bent ( ) ( url , null , {
165+ headers : options . headers || { }
166+ } ) ;
167+
168+ const userRoot = options . root || 'home:/.packages' ; // FIXME: Client-side
169+ const target = await realpath ( `${ userRoot } /${ name } ` , user ) ;
170+ const root = await realpath ( userRoot , user ) ;
171+ const manifest = await realpath ( `${ userRoot } /metadata.json` , user ) ;
172+
173+ if ( await fs . exists ( target ) ) {
174+ throw new Error ( 'Target already exists' ) ;
175+ }
176+
177+ if ( options . system ) {
178+ throw new Error ( 'System packages not yet implemented' ) ;
179+ }
180+
181+ await fs . mkdir ( target ) ;
182+ await extract ( stream , target ) ;
183+
184+ const filenames = await fg ( root + '/*/metadata.json' ) ;
185+ const metadatas = await Promise . all ( filenames . map ( f => fs . readJson ( f ) ) ) ;
186+
187+ await fs . writeJson ( manifest , metadatas ) ;
150188 }
151189
152190 /**
0 commit comments