Skip to content

Commit

Permalink
feature(build-infra): ui to submit builds
Browse files Browse the repository at this point in the history
  • Loading branch information
heapwolf committed Apr 30, 2024
1 parent a38d295 commit 1631070
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 61 deletions.
12 changes: 5 additions & 7 deletions src/components/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class DialogAccount extends TonicDialog {
return
}

console.log('GOT RESPONSE FROM STRIPE PAGE', event.data)

try {
const res = await fetch('https://api.socketsupply.co/signup', {
method: 'POST',
Expand All @@ -40,19 +38,19 @@ class DialogAccount extends TonicDialog {
body: JSON.stringify(event.data)
})

console.log('SIGNUP RESPONSE', res)

if (res.ok) {
const { data: dataUser } = await this.db.state.get('user')
const app = this.props.parent
const { data: dataUser } = await app.db.state.get('user')
dataUser.buildKeys = await res.json()
console.log('dataUser', dataUser)
await this.db.state.put('user', dataUser)
await app.db.state.put('user', dataUser)
await this.hide()
return this.resolve({ data: true })
}
} catch (err) {
if (err.name === "AbortError") {
this.resolve({ data: event.data })
await this.hide()
return this.resolve({ err: true })
}
console.log(err)
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/confirm.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Tonic from '@socketsupply/tonic'
import { TonicDialog } from '@socketsupply/components/dialog'

class DialogConfirm extends TonicDialog {
Expand Down Expand Up @@ -51,7 +52,7 @@ class DialogConfirm extends TonicDialog {
<header>${title}</header>
<main>
<div class="message">
${message}
${Tonic.unsafeRawString(message)}
</div>
${this.renderCheckbox()}
</main>
Expand Down
2 changes: 1 addition & 1 deletion src/components/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ class AppProject extends Tonic {
const fullPath = path.join(dirPath, entry.name)
const oldChild = this.getNodeByProperty('id', fullPath, oldState)

if (entry.name === '.git') continue
if (entry.name[0] === '.') continue

const child = {
id: fullPath,
Expand Down
10 changes: 5 additions & 5 deletions src/components/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ class AppProperties extends Tonic {
id="build-target"
label="Build"
>
<tonic-checkbox data-section="build-target" id="arch-android" checked="${process.platform === 'android'}" label="Android" title="Android"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-darwin" checked="${process.platform === 'darwin'}" label="MacOS" title="MacOS/Darwin"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-ios" checked="${process.platform === 'ios'}" label="iOS" title="iOS"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-linux" checked="${process.platform === 'linux'}" label="Linux" title="Linux"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-win32" checked="${process.platform === 'win32'}" label="Windows" title="Windows"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-android" data-arch="android" checked="${String(process.platform === 'android')}" label="Android" title="Android"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-darwin" data-arch="darwin" checked="${String(process.platform === 'darwin')}" label="MacOS" title="MacOS/Darwin"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-ios" data-arch="ios" checked="${String(process.platform === 'ios')}" label="iOS" title="iOS"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-linux" data-arch="linux" checked="${String(process.platform === 'linux')}" label="Linux" title="Linux"></tonic-checkbox>
<tonic-checkbox data-section="build-target" id="arch-win32" data-arch="win32" checked="${String(process.platform === 'win32')}" label="Windows" title="Windows"></tonic-checkbox>
</tonic-accordion-section>
<tonic-accordion-section
Expand Down
8 changes: 7 additions & 1 deletion src/css/component-confirm.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dialog-confirm header {
height: 46px;
text-align: center;
padding: 14px;
font-size: 12px;
font-size: 14px;
color: var(--tonic-info);
}

Expand Down Expand Up @@ -41,3 +41,9 @@ dialog-confirm main {
padding: 4% 6%;
text-align: left;
}

dialog-confirm main .message {
font-family: var(--tonic-body);
letter-spacing: 0.2px;
font-size: 16px;
}
188 changes: 142 additions & 46 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import components from '@socketsupply/components'
import Indexed from '@socketsupply/indexed'

import { Patch } from './git-data.js'
import { cp, rm } from './lib/fs.js'
import { rm } from './lib/fs.js'

import { RelativeDate } from './components/relative-date.js'
import { GitStatus } from './components/git-status.js'
Expand Down Expand Up @@ -315,6 +315,19 @@ class AppView extends Tonic {
}
}

async getBin () {
const runtime = await import(`npm:@socketsupply/socket-${os.platform()}-${os.arch()}`)
const ssc = path.join(process.cwd(), runtime.bin.ssc.replace(globalThis.location.origin, ''))

try {
await fs.promises.access('/Applications/Xcode.app/Contents/Developer/usr/bin/git', fs.constants.X_OK)
} catch (err) {
console.error(err)
}

return ssc
}

async createProject (opts = {}) {
const name = opts.name || 'project-' + Math.random().toString(16).slice(2, 8)
const bundleId = 'com.' + name
Expand All @@ -340,16 +353,8 @@ class AppView extends Tonic {
await this.db.projects.put(bundleId, project)
await fs.promises.mkdir(project.path, { recursive: true })

const runtime = await import(`npm:@socketsupply/socket-${os.platform()}-${os.arch()}`)
const ssc = path.join(process.cwd(), runtime.bin.ssc.replace(globalThis.location.origin, ''))
console.log({ ssc })
try {
await fs.promises.access('/Applications/Xcode.app/Contents/Developer/usr/bin/git', fs.constants.X_OK)
} catch (err) {
console.error(err)
}
try {
await exec(`${ssc} init`, { cwd: project.path })
await exec(`${await this.getBin()} init`, { cwd: project.path })

console.log(await exec('/Applications/Xcode.app/Contents/Developer/usr/bin/git init', { cwd: project.path }))
} catch (err) {
Expand Down Expand Up @@ -484,46 +489,132 @@ class AppView extends Tonic {
}
}

async packageProject () {
const coDialogConfirm = document.querySelector('dialog-confirm')
const result = await coDialogConfirm.prompt({
type: 'question',
message: `You're on ${process.platform} but you're targeting other operating systems. Do you want to use the Socket Supply Co. build service to handle this for you?`,
buttons: [
{ label: 'Abandon', value: 'abandon' },
{ label: 'Continue', value: 'consent' }
]
})
async buildProject () {
const { data: dataUser } = await this.db.state.get('user')

if (!result.abandon && !result.consent) return

if (result.consent) {
//
// Check if the user has an account if not, sign up for one
//
const { data: dataUser } = await this.db.state.get('user')
if (!dataUser.card) {
const coDialogAccount = document.querySelector('dialog-account')
const { err, data } = await coDialogAccount.prompt()

if (err) {
//
// show a new prompt with the error and the option to call this.packageProject() again
//
return
const architectures = [...document.querySelectorAll('#build-target tonic-checkbox')]
.filter(co => co.value)
.map(co => co.dataset.arch)

const invalidMacOS = new Set(['linux', 'win32'])
const invalidWin32 = new Set(['ios', 'darwin', 'linux'])
const invalidLinux = new Set(['ios', 'darwin', 'win32'])

let needsBuildService = false

if (process.platform === 'darwin' && architectures.some(s => invalidMacOS.has(s))) needsBuildService = true
if (process.platform === 'win32' && architectures.some(s => invalidWin32.has(s))) needsBuildService = true
if (process.platform === 'linux' && architectures.some(s => invalidLinux.has(s))) needsBuildService = true

if (needsBuildService) {
const platform = process.platform === 'darwin' ? 'MacOS' : process.platform
const coDialogConfirm = document.querySelector('dialog-confirm')
const result = await coDialogConfirm.prompt({
type: 'question',
message: `
You're using ${platform} but you're trying to build for other operating systems or compute architectures.
<br><br>
Do you want to use our <b>Build Service</b> to handle this for you?
`,
buttons: [
{ label: 'cancel', value: 'abandon' },
{ label: 'ok', value: 'consent' }
]
})

if (!result.abandon && !result.consent) return

if (result.consent) {
//
// Check if the user has an account if not, sign up for one
//
if (!dataUser.buildKeys) {
const coDialogAccount = document.querySelector('dialog-account')
const { err } = await coDialogAccount.prompt()

if (err) {
await coDialogConfirm.prompt({
type: 'question',
message: err.message,
buttons: [
{ label: 'ok', value: 'cancel' }
]
})

this.buildProject()
return
}
}
}

//
// User has an account. go ahead and submit the request for a build
//

//
// Apparently tar has been available on windows since v10. Tar it,
// base64 encode it, and add it to the manifest as a payload.
//
const tar = spawn('tar', ['-cvf', '-', this.state.currentProject.id])
const buffer = Buffer.alloc(0)

tar.stdout.on('data', data => {
buffer = Buffer.concat([buffer, data])
})

tar.stderr.on('data', data => {
term.error(data.toString())
})

tar.on('close', (code) => {
term.info(`tar process exited with code ${code}`)
})

//
// This tells us what architectures you want to build for, what time
// you're trying to send it, your public key and the payload you want built.
//
const manifest = {
architectures,
ctime: Date.now(),
pk: dataUser.buildKeys.pk,
data: buffer.toString('base64')
}

const bytes = Buffer.from(JSON.stringify(manifest))
manifest.sig = Encryption.sign(bytes, dataUser.buildKeys.sk)

try {
const res = await fetch('https://api.socketsupply.co/build', {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(manifest)
})

if (res.ok) {
const app = this.props.parent
const { data: dataUser } = await app.db.state.get('user')
dataUser.buildKeys = await res.json()
await app.db.state.put('user', dataUser)
await this.hide()
return this.resolve({ data: true })
}
} catch (err) {
console.log(err)
}
}
return
}

//
// run the build locally. also, it's going to be ready quite
// quickly, so just reveal it when it's ready.
await this.spawnSSC('build')

const w = await application.getCurrentWindow()
await w.revealFile(this.state.currentProject.id)
}

async runSSC (...args) {
async spawnSSC (...args) {
const { promise, resolve } = Promise.withResolvers()
const term = document.querySelector('app-terminal')
term.info(`ssc ${args.join(' ')}`)
term.info(`${await this.getBin()} ${args.join(' ')}`)

if (this.childprocess && !this.childprocess.killed && this.childprocess.exitCode !== null) {
this.childprocess.kill('SIGKILL')
Expand All @@ -541,7 +632,7 @@ class AppView extends Tonic {
term.info('Running new instance of app')
const cwd = this.state.currentProject.id
const env = { SSC_PARENT_LOG_SOCKET: process.env.SSC_LOG_SOCKET }
const c = this.childprocess = await spawn('ssc', args, { cwd, env })
const c = this.childprocess = await spawn(await this.getBin(), args, { cwd, env })

c.stdout.on('data', data => {
term.writeln(Buffer.from(data).toString().trim())
Expand All @@ -554,12 +645,16 @@ class AppView extends Tonic {
c.once('exit', (code) => {
term.writeln(`OK! ${code}`)
this.childprocess = null
resolve()
})

c.once('error', (code) => {
term.writeln(`NOT OK! ${code}`)
this.childprocess = null
resolve()
})

return promise
}

async initMenu () {
Expand Down Expand Up @@ -756,11 +851,11 @@ class AppView extends Tonic {

// TODO(@heapwolf) check all checked archs in properties panel

this.runSSC(...args)
await this.spawnSSC(...args)
}

if (event === 'package') {
this.packageProject()
this.buildProject()
}

if (event === 'preview-mode') {
Expand Down Expand Up @@ -886,6 +981,7 @@ class AppView extends Tonic {
id="dialog-account"
width="70%"
height="55%"
parent=${this}
>
</dialog-account>
Expand Down

0 comments on commit 1631070

Please sign in to comment.