mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-25 18:33:11 +00:00
started on GithubService
This commit is contained in:
parent
5ded34e668
commit
93c0e8f50b
@ -123,6 +123,7 @@ TODO:
|
|||||||
- quantify verilog "graph iterations"
|
- quantify verilog "graph iterations"
|
||||||
- toolbar overlaps scope
|
- toolbar overlaps scope
|
||||||
- CPU debugging
|
- CPU debugging
|
||||||
|
- use $readmem for inline asm programs?
|
||||||
- single-stepping vector games makes screen fade
|
- single-stepping vector games makes screen fade
|
||||||
- break on stack overflow, bad op, bad access, etc
|
- break on stack overflow, bad op, bad access, etc
|
||||||
- PPU/TIA register write visualization
|
- PPU/TIA register write visualization
|
||||||
@ -132,6 +133,11 @@ TODO:
|
|||||||
- allow "include graphics.asm" instead of "include project/graphics.asm"
|
- allow "include graphics.asm" instead of "include project/graphics.asm"
|
||||||
- chrome looks blurry on vcs
|
- chrome looks blurry on vcs
|
||||||
- don't have to include bootstrap-tourist each time?
|
- don't have to include bootstrap-tourist each time?
|
||||||
|
- don't have to include firebase always?
|
||||||
|
- Github
|
||||||
|
- write/read metadata w/ main file
|
||||||
|
- push/pull changes
|
||||||
|
- gh-pages branch with embedded
|
||||||
|
|
||||||
|
|
||||||
WEB WORKER FORMAT
|
WEB WORKER FORMAT
|
||||||
|
66
index.html
66
index.html
@ -20,8 +20,24 @@ body {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="css/ui.css">
|
<link rel="stylesheet" href="css/ui.css">
|
||||||
|
|
||||||
|
<!-- google analytics -->
|
||||||
|
<script>
|
||||||
|
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||||
|
if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||||
|
ga('create', 'UA-54497476-9', 'auto');
|
||||||
|
ga('set', 'anonymizeIp', true);
|
||||||
|
ga('send', 'pageview');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
<!-- firebase libs -->
|
||||||
|
<script defer src="https://www.gstatic.com/firebasejs/5.11.1/firebase-app.js"></script>
|
||||||
|
<script defer src="https://www.gstatic.com/firebasejs/5.11.1/firebase-auth.js"></script>
|
||||||
|
<script defer src="config.js"></script>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- for file upload -->
|
<!-- for file upload -->
|
||||||
@ -54,7 +70,7 @@ body {
|
|||||||
<li><a class="dropdown-item" href="/login.html">Login to GitHub...</a></li>
|
<li><a class="dropdown-item" href="/login.html">Login to GitHub...</a></li>
|
||||||
<hr>
|
<hr>
|
||||||
<li><a class="dropdown-item" href="#" id="item_github_import">Import Project from GitHub...</a></li>
|
<li><a class="dropdown-item" href="#" id="item_github_import">Import Project from GitHub...</a></li>
|
||||||
<li><a class="dropdown-item" href="#" id="item_github_connect">Publish Project on GitHub...</a></li>
|
<li><a class="dropdown-item" href="#" id="item_github_publish">Publish Project on GitHub...</a></li>
|
||||||
<hr>
|
<hr>
|
||||||
<li><a class="dropdown-item" href="#" id="item_github_push">Push Changes to Repository...</a></li>
|
<li><a class="dropdown-item" href="#" id="item_github_push">Push Changes to Repository...</a></li>
|
||||||
<hr>
|
<hr>
|
||||||
@ -234,6 +250,10 @@ body {
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
Please wait...
|
Please wait...
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar progress-bar-striped active" role="progressbar" id="pleaseWaitProgressBar">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -293,17 +313,29 @@ body {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="connectGithubModal" class="modal fade">
|
<div id="publishGithubModal" class="modal fade">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3 class="modal-title">Publish Project on GitHub</h3>
|
<h3 class="modal-title">Publish Project on GitHub</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>This will migrate your existing files to a GitHub repository.</p>
|
<p>This will migrate your existing files to a new GitHub repository.</p>
|
||||||
<p><input id="connectGithubURL" size="40" placeholder="Enter a project name"></input></p>
|
<p><input id="githubRepoName" size="50" placeholder="Enter a project name"></input></p>
|
||||||
<p><button type="button" class="btn btn-primary" id="connectGithubButton">Upload Project</button></p>
|
<p><input id="githubRepoDesc" size="50" placeholder="Enter a project description"></input></p>
|
||||||
<p>If the destination repository does not exist, it will be created.</p>
|
<p>Your repository will be <select id="githubRepoPrivate">
|
||||||
|
<option value="public">Public</option>
|
||||||
|
<option value="private">Private</option>
|
||||||
|
</select></p>
|
||||||
|
<p>License: <select id="githubRepoLicense">
|
||||||
|
<option value="">Will decide later</option>
|
||||||
|
<option value="cc0-1.0">CC Zero (public domain)</option>
|
||||||
|
<option value="mit">MIT (public domain, must preserve notices)</option>
|
||||||
|
<option value="cc-by-4.0">CC BY (must attribute)</option>
|
||||||
|
<option value="cc-by-sa-4.0">CC BY-SA (must attribute, use same license)</option>
|
||||||
|
<option value="gpl-3.0">GPL v3 (must publish source)</option>
|
||||||
|
</select></p>
|
||||||
|
<p><button type="button" class="btn btn-primary" id="publishGithubButton">Upload Project</button></p>
|
||||||
<p>Your existing file will be moved to a new folder in the IDE.</p>
|
<p>Your existing file will be moved to a new folder in the IDE.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@ -312,6 +344,22 @@ body {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="pushGithubModal" class="modal fade">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title">Push Project Changes to GitHub</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p><input id="githubCommitMsg" size="50" placeholder="Enter a commit message"></input></p>
|
||||||
|
<p><button type="button" class="btn btn-primary" id="pushGithubButton">Push Changes</button></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="jquery/jquery-3.4.1.min.js"></script>
|
<script src="jquery/jquery-3.4.1.min.js"></script>
|
||||||
|
|
||||||
@ -381,6 +429,7 @@ function require(modname) {
|
|||||||
<script src="gen/recorder.js"></script>
|
<script src="gen/recorder.js"></script>
|
||||||
<script src="gen/waveform.js"></script>
|
<script src="gen/waveform.js"></script>
|
||||||
<script src="gen/pixed/pixeleditor.js"></script>
|
<script src="gen/pixed/pixeleditor.js"></script>
|
||||||
|
<script src="gen/services.js"></script>
|
||||||
<script src="gen/ui.js"></script>
|
<script src="gen/ui.js"></script>
|
||||||
<!-- <script src="src/audio/votrax.js"></script> -->
|
<!-- <script src="src/audio/votrax.js"></script> -->
|
||||||
<!-- <script src="local/lzg.js"></script> -->
|
<!-- <script src="local/lzg.js"></script> -->
|
||||||
@ -405,10 +454,5 @@ $( ".dropdown-submenu" ).click(function(event) {
|
|||||||
*/
|
*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- firebase libs -->
|
|
||||||
<script defer src="https://www.gstatic.com/firebasejs/5.11.1/firebase-app.js"></script>
|
|
||||||
<script defer src="https://www.gstatic.com/firebasejs/5.11.1/firebase-auth.js"></script>
|
|
||||||
<script defer src="config.js"></script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"jsdom": "^12.2.0",
|
"jsdom": "^12.2.0",
|
||||||
"lzg": "^1.0.x",
|
"lzg": "^1.0.x",
|
||||||
"mocha": "^5.2.x",
|
"mocha": "^5.2.x",
|
||||||
|
"octokat": "^0.10.0",
|
||||||
"pngjs": "^3.3.3",
|
"pngjs": "^3.3.3",
|
||||||
"typescript": "^3.3.3",
|
"typescript": "^3.3.3",
|
||||||
"wavedrom-cli": "^0.5.x"
|
"wavedrom-cli": "^0.5.x"
|
||||||
|
@ -330,9 +330,11 @@ export class CodeProject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stripLocalPath(path : string) : string {
|
stripLocalPath(path : string) : string {
|
||||||
var folder = getFolderForPath(this.mainPath);
|
if (this.mainPath) {
|
||||||
if (folder != '' && path.startsWith(folder)) {
|
var folder = getFolderForPath(this.mainPath);
|
||||||
path = path.substring(folder.length+1);
|
if (folder != '' && path.startsWith(folder)) {
|
||||||
|
path = path.substring(folder.length+1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
196
src/services.ts
Normal file
196
src/services.ts
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
|
||||||
|
import { getFolderForPath, isProbablyBinary, stringToByteArray } from "./util";
|
||||||
|
import { FileData } from "./workertypes";
|
||||||
|
import { CodeProject } from "./project";
|
||||||
|
|
||||||
|
// in index.html
|
||||||
|
declare var exports;
|
||||||
|
declare var firebase;
|
||||||
|
|
||||||
|
interface GHSession {
|
||||||
|
url : string;
|
||||||
|
user : string;
|
||||||
|
reponame : string;
|
||||||
|
repo : any;
|
||||||
|
prefix : string;
|
||||||
|
paths? : string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GithubService {
|
||||||
|
|
||||||
|
github;
|
||||||
|
store;
|
||||||
|
project : CodeProject;
|
||||||
|
branch : string = "master";
|
||||||
|
|
||||||
|
constructor(github, store, project : CodeProject) {
|
||||||
|
this.github = github;
|
||||||
|
this.store = store;
|
||||||
|
this.project = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
isFileIgnored(s : string) : boolean {
|
||||||
|
s = s.toUpperCase();
|
||||||
|
if (s.startsWith("LICENSE")) return true;
|
||||||
|
if (s.startsWith("README")) return true;
|
||||||
|
if (s.startsWith(".")) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseGithubURL(ghurl:string) {
|
||||||
|
var toks = ghurl.split('/');
|
||||||
|
console.log(toks);
|
||||||
|
if (toks.length < 5) return null;
|
||||||
|
if (toks[0] != 'https:') return null;
|
||||||
|
if (toks[2] != 'github.com') return null;
|
||||||
|
return {user:toks[3], repo:toks[4]};
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrefix(user, reponame) : string {
|
||||||
|
return 'shared/' + user + '-' + reponame + '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
getGithubRepo(ghurl:string) : Promise<GHSession> {
|
||||||
|
return new Promise( (yes,no) => {
|
||||||
|
var urlparse = this.parseGithubURL(ghurl);
|
||||||
|
if (!urlparse) {
|
||||||
|
no("Please enter a valid GitHub URL.");
|
||||||
|
}
|
||||||
|
var sess = {
|
||||||
|
url: ghurl,
|
||||||
|
user: urlparse.user,
|
||||||
|
reponame: urlparse.repo,
|
||||||
|
prefix: this.getPrefix(urlparse.user, urlparse.repo),
|
||||||
|
repo: this.github.repos(urlparse.user, urlparse.repo)
|
||||||
|
};
|
||||||
|
yes(sess);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind a folder path to the Github URL in local storage
|
||||||
|
bind(sess : GHSession, dobind : boolean) {
|
||||||
|
var key = '__github_url_' + sess.prefix;
|
||||||
|
// TODO: this doesn't work b/c it binds the entire root to a url
|
||||||
|
if (!key.endsWith('/'))
|
||||||
|
key = key + '/';
|
||||||
|
console.log('bind', key, dobind);
|
||||||
|
if (dobind)
|
||||||
|
localStorage.setItem(key, sess.url);
|
||||||
|
else
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
getBoundURL(path : string) : string {
|
||||||
|
var p = getFolderForPath(path);
|
||||||
|
var key = '__github_url_' + p + '/';
|
||||||
|
console.log(key);
|
||||||
|
return localStorage.getItem(key) as string; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
import(ghurl:string) : Promise<GHSession> {
|
||||||
|
var sess : GHSession;
|
||||||
|
return this.getGithubRepo(ghurl).then( (session) => {
|
||||||
|
sess = session;
|
||||||
|
return sess.repo.commits(this.branch).fetch();
|
||||||
|
})
|
||||||
|
.then( (sha) => {
|
||||||
|
return sess.repo.git.trees(sha.sha).fetch();
|
||||||
|
})
|
||||||
|
.then( (tree) => {
|
||||||
|
let blobreads = [];
|
||||||
|
sess.paths = [];
|
||||||
|
tree.tree.forEach( (item) => {
|
||||||
|
console.log(item.path, item.type, item.size);
|
||||||
|
sess.paths.push(item.path);
|
||||||
|
if (item.type == 'blob' && !this.isFileIgnored(item.path)) {
|
||||||
|
var read = sess.repo.git.blobs(item.sha).readBinary().then( (blob) => {
|
||||||
|
var path = sess.prefix + item.path;
|
||||||
|
var size = item.size;
|
||||||
|
var isBinary = isProbablyBinary(blob);
|
||||||
|
var data = isBinary ? stringToByteArray(blob) : blob; //byteArrayToUTF8(blob);
|
||||||
|
return this.store.setItem(path, data);
|
||||||
|
});
|
||||||
|
blobreads.push(read);
|
||||||
|
} else {
|
||||||
|
console.log("ignoring " + item.path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Promise.all(blobreads);
|
||||||
|
})
|
||||||
|
.then( (blobs) => {
|
||||||
|
this.bind(sess, true);
|
||||||
|
return sess;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
publish(reponame:string, desc:string, license:string, isprivate:boolean) : Promise<GHSession> {
|
||||||
|
return this.github.user.repos.create({
|
||||||
|
name: reponame,
|
||||||
|
description: desc,
|
||||||
|
private: isprivate,
|
||||||
|
auto_init: true,
|
||||||
|
license_template: license
|
||||||
|
})
|
||||||
|
.then( (repo) => {
|
||||||
|
let sess = {
|
||||||
|
url: repo.htmlUrl,
|
||||||
|
user: repo.owner.login,
|
||||||
|
reponame: reponame,
|
||||||
|
repo: repo,
|
||||||
|
prefix : ''
|
||||||
|
};
|
||||||
|
this.bind(sess, true);
|
||||||
|
return sess;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
commitPush( ghurl:string, message:string, files:{path:string,data:FileData}[] ) : Promise<GHSession> {
|
||||||
|
var sess : GHSession;
|
||||||
|
var repo;
|
||||||
|
var head;
|
||||||
|
var tree;
|
||||||
|
return this.getGithubRepo(ghurl).then( (session) => {
|
||||||
|
sess = session;
|
||||||
|
repo = sess.repo;
|
||||||
|
return repo.git.refs.heads(this.branch).fetch();
|
||||||
|
}).then( (_head) => {
|
||||||
|
head = _head;
|
||||||
|
return repo.git.trees(head.object.sha).fetch();
|
||||||
|
}).then( (_tree) => {
|
||||||
|
tree = _tree;
|
||||||
|
return Promise.all(files.map( (file) => {
|
||||||
|
return repo.git.blobs.create({
|
||||||
|
content: file.data,
|
||||||
|
encoding: 'utf-8'
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}).then( (blobs) => {
|
||||||
|
return repo.git.trees.create({
|
||||||
|
tree: files.map( (file, index) => {
|
||||||
|
return {
|
||||||
|
path: file.path,
|
||||||
|
mode: '100644',
|
||||||
|
type: 'blob',
|
||||||
|
sha: blobs[index]['sha']
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
base_tree: tree.sha
|
||||||
|
});
|
||||||
|
}).then( (tree) => {
|
||||||
|
return repo.git.commits.create({
|
||||||
|
message: message,
|
||||||
|
tree: tree.sha,
|
||||||
|
parents: [
|
||||||
|
head.object.sha
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}).then( (commit) => {
|
||||||
|
return repo.git.refs.heads(this.branch).update({
|
||||||
|
sha: commit.sha
|
||||||
|
});
|
||||||
|
}).then( (update) => {
|
||||||
|
return sess;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -43,6 +43,7 @@ function copyFromVer2xStorageFormat(platformid:string, newstore, callback:(store
|
|||||||
// no files to convert?
|
// no files to convert?
|
||||||
if (keys.length == 0) {
|
if (keys.length == 0) {
|
||||||
localStorage.setItem(alreadyMigratedKey, 'true');
|
localStorage.setItem(alreadyMigratedKey, 'true');
|
||||||
|
callback(newstore);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// convert function
|
// convert function
|
||||||
|
173
src/ui.ts
173
src/ui.ts
@ -12,11 +12,12 @@ import { PLATFORMS, EmuHalt, Toolbar } from "./emu";
|
|||||||
import * as Views from "./views";
|
import * as Views from "./views";
|
||||||
import { createNewPersistentStore } from "./store";
|
import { createNewPersistentStore } from "./store";
|
||||||
import { getFilenameForPath, getFilenamePrefix, highlightDifferences, invertMap, byteArrayToString, compressLZG,
|
import { getFilenameForPath, getFilenamePrefix, highlightDifferences, invertMap, byteArrayToString, compressLZG,
|
||||||
byteArrayToUTF8, isProbablyBinary, getWithBinary, stringToByteArray } from "./util";
|
byteArrayToUTF8, isProbablyBinary, getWithBinary } from "./util";
|
||||||
import { StateRecorderImpl } from "./recorder";
|
import { StateRecorderImpl } from "./recorder";
|
||||||
|
import { GithubService } from "./services";
|
||||||
|
|
||||||
// external libs (TODO)
|
// external libs (TODO)
|
||||||
declare var Tour, GIF, saveAs, JSZip, Mousetrap, Split, GitHub;
|
declare var Tour, GIF, saveAs, JSZip, Mousetrap, Split, firebase;
|
||||||
// in index.html
|
// in index.html
|
||||||
declare var exports;
|
declare var exports;
|
||||||
|
|
||||||
@ -366,84 +367,109 @@ function getCurrentEditorFilename() : string {
|
|||||||
|
|
||||||
// GITHUB stuff (TODO: move)
|
// GITHUB stuff (TODO: move)
|
||||||
|
|
||||||
|
var githubService : GithubService;
|
||||||
|
|
||||||
|
function getCookie(name) {
|
||||||
|
var nameEQ = name + "=";
|
||||||
|
var ca = document.cookie.split(';');
|
||||||
|
for(var i=0;i < ca.length;i++) {
|
||||||
|
var c = ca[i];
|
||||||
|
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||||
|
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGithubService() {
|
||||||
|
if (!githubService) {
|
||||||
|
loadScript("lib/octokat.js", () => {
|
||||||
|
// get github API key from cookie
|
||||||
|
var ghkey = getCookie('__github_key');
|
||||||
|
var ghopts = {token:ghkey};
|
||||||
|
githubService = new GithubService(new exports['Octokat'](ghopts), store, current_project);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return githubService;
|
||||||
|
}
|
||||||
|
|
||||||
function _importProjectFromGithub(e) {
|
function _importProjectFromGithub(e) {
|
||||||
var githuburl_ta = $("#importGithubURL");
|
getGithubService(); // load it
|
||||||
var modal = $("#importGithubModal");
|
var modal = $("#importGithubModal");
|
||||||
var btn = $("#importGithubButton");
|
var btn = $("#importGithubButton");
|
||||||
modal.modal('show');
|
modal.modal('show');
|
||||||
btn.off('click').on('click', () => {
|
btn.off('click').on('click', () => {
|
||||||
importFromGithub(githuburl_ta.val());
|
var githuburl = $("#importGithubURL").val()+"";
|
||||||
});
|
getGithubService().import(githuburl).then( (sess) => {
|
||||||
}
|
// TODO : redirect to main file
|
||||||
|
modal.modal('hide');
|
||||||
function _connectProjectToGithub(e) {
|
}).catch( (e) => {
|
||||||
var githuburl_ta = $("#connectGithubURL");
|
modal.modal('hide');
|
||||||
var modal = $("#connectGithubModal");
|
alert("Could not import " + githuburl + ": " + e);
|
||||||
var btn = $("#connectGithubButton");
|
|
||||||
modal.modal('show');
|
|
||||||
btn.off('click').on('click', () => {
|
|
||||||
connectToGithub(githuburl_ta.val());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseGithubURL(ghurl) {
|
|
||||||
var toks = ghurl.split('/');
|
|
||||||
console.log(toks)
|
|
||||||
if (toks.length < 5) return null;
|
|
||||||
if (toks[0] != 'https:') return null;
|
|
||||||
if (toks[2] != 'github.com') return null;
|
|
||||||
return {user:toks[3], repo:toks[4]};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGithubRepo(ghurl, callback) {
|
|
||||||
var urlparse = parseGithubURL(ghurl);
|
|
||||||
if (!urlparse) {
|
|
||||||
alert("Please enter a valid GitHub URL.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loadScript("lib/octokat.js", () => {
|
|
||||||
var github = new exports['Octokat']();
|
|
||||||
var prefix = 'shared/' + urlparse.user + '-' + urlparse.repo + '/';
|
|
||||||
var repo = github.repos(urlparse.user, urlparse.repo);
|
|
||||||
callback(github, repo, prefix);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function importFromGithub(ghurl) {
|
|
||||||
getGithubRepo(ghurl, (github, repo, prefix) => {
|
|
||||||
repo.commits('master').fetch().then( (sha) => {
|
|
||||||
repo.git.trees(sha.sha).fetch().then( (tree) => {
|
|
||||||
tree.tree.forEach( (item) => {
|
|
||||||
console.log(item);
|
|
||||||
if (item.type == 'blob') {
|
|
||||||
repo.git.blobs(item.sha).readBinary().then( (blob) => {
|
|
||||||
var path = prefix + item.path;
|
|
||||||
var size = item.size;
|
|
||||||
var isBinary = isProbablyBinary(blob);
|
|
||||||
var data = isBinary ? stringToByteArray(blob) : blob; //byteArrayToUTF8(blob);
|
|
||||||
// TODO projectWindows.updateFile(path, data);
|
|
||||||
store.setItem(path, data);
|
|
||||||
// TODO; wait for set?
|
|
||||||
console.log(path, size, isBinary, typeof blob);
|
|
||||||
// TODO: redirect to main file?
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectToGithub(ghurl) {
|
function _publishProjectToGithub(e) {
|
||||||
getGithubRepo(ghurl, (github, repo, prefix) => {
|
getGithubService(); // load it
|
||||||
// TODO
|
var modal = $("#publishGithubModal");
|
||||||
|
var btn = $("#publishGithubButton");
|
||||||
|
modal.modal('show');
|
||||||
|
btn.off('click').on('click', () => {
|
||||||
|
var name = $("#githubRepoName").val()+"";
|
||||||
|
var desc = $("#githubRepoDesc").val()+"";
|
||||||
|
var priv = $("#githubRepoPrivate").val() == 'private';
|
||||||
|
var license = $("#githubRepoLicense").val()+"";
|
||||||
|
getGithubService().publish(name, desc, license, priv).then( (sess) => {
|
||||||
|
modal.modal('hide');
|
||||||
|
// TODO: commit files
|
||||||
|
// TODO: migrate project files
|
||||||
|
console.log(sess);
|
||||||
|
alert("Created repository at " + sess.url);
|
||||||
|
pushChangesToGithub('initial import from 8bitworkshop.com');
|
||||||
|
}).catch( (e) => {
|
||||||
|
modal.modal('hide');
|
||||||
|
alert("Could not create GitHub repository: " + e);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _pushProjectToGithub(e) {
|
||||||
|
getGithubService(); // load it
|
||||||
|
var modal = $("#pushGithubModal");
|
||||||
|
var btn = $("#pushGithubButton");
|
||||||
|
modal.modal('show');
|
||||||
|
btn.off('click').on('click', () => {
|
||||||
|
var commitMsg = $("#githubCommitMsg").val()+"";
|
||||||
|
modal.modal('hide');
|
||||||
|
pushChangesToGithub(commitMsg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushChangesToGithub(message:string) {
|
||||||
|
var ghurl = getGithubService().getBoundURL(current_project.mainPath);
|
||||||
|
console.log("Github URL: " + ghurl);
|
||||||
|
if (!ghurl) {
|
||||||
|
alert("This project is not bound to a GitHub project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// build file list for push
|
||||||
|
var files = [];
|
||||||
|
for (var path in current_project.filedata) {
|
||||||
|
var newpath = current_project.stripLocalPath(path);
|
||||||
|
files.push({path:newpath, data:current_project.filedata[path]});
|
||||||
|
}
|
||||||
|
// push files
|
||||||
|
setWaitDialog(true);
|
||||||
|
getGithubService().commitPush(ghurl, message, files).then( (sess) => {
|
||||||
|
setWaitDialog(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove?
|
||||||
function loadSharedGist(gistkey : string) {
|
function loadSharedGist(gistkey : string) {
|
||||||
loadScript("lib/octokat.js", () => {
|
loadScript("lib/octokat.js", () => {
|
||||||
var github = new exports['Octokat']();
|
var github = new exports['Octokat']();
|
||||||
var gist = github.gists(gistkey);
|
var gist = this.github.gists(gistkey);
|
||||||
gist.fetch().done( (val) => {
|
gist.fetch().done( (val) => {
|
||||||
var filename;
|
var filename;
|
||||||
var newid;
|
var newid;
|
||||||
@ -983,12 +1009,17 @@ function updateDebugWindows() {
|
|||||||
|
|
||||||
function setWaitDialog(b : boolean) {
|
function setWaitDialog(b : boolean) {
|
||||||
if (b) {
|
if (b) {
|
||||||
|
$("#pleaseWaitProgressBar").hide();
|
||||||
$("#pleaseWaitModal").modal('show');
|
$("#pleaseWaitModal").modal('show');
|
||||||
} else {
|
} else {
|
||||||
$("#pleaseWaitModal").modal('hide');
|
$("#pleaseWaitModal").modal('hide');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWaitProgress(prog : number) {
|
||||||
|
$("#pleaseWaitProgressBar").css('width', (prog*100)+'%').show();
|
||||||
|
}
|
||||||
|
|
||||||
var recordingVideo = false;
|
var recordingVideo = false;
|
||||||
function _recordVideo() {
|
function _recordVideo() {
|
||||||
if (recordingVideo) return;
|
if (recordingVideo) return;
|
||||||
@ -1013,7 +1044,10 @@ function _recordVideo() {
|
|||||||
rotate: rotate
|
rotate: rotate
|
||||||
});
|
});
|
||||||
var img = $('#videoPreviewImage');
|
var img = $('#videoPreviewImage');
|
||||||
gif.on('finished', function(blob) {
|
gif.on('progress', (prog) => {
|
||||||
|
setWaitProgress(prog);
|
||||||
|
});
|
||||||
|
gif.on('finished', (blob) => {
|
||||||
img.attr('src', URL.createObjectURL(blob));
|
img.attr('src', URL.createObjectURL(blob));
|
||||||
setWaitDialog(false);
|
setWaitDialog(false);
|
||||||
_resume();
|
_resume();
|
||||||
@ -1198,7 +1232,8 @@ function setupDebugControls() {
|
|||||||
$("#item_new_file").click(_createNewFile);
|
$("#item_new_file").click(_createNewFile);
|
||||||
$("#item_upload_file").click(_uploadNewFile);
|
$("#item_upload_file").click(_uploadNewFile);
|
||||||
$("#item_github_import").click(_importProjectFromGithub);
|
$("#item_github_import").click(_importProjectFromGithub);
|
||||||
$("#item_github_connect").click(_connectProjectToGithub);
|
$("#item_github_publish").click(_publishProjectToGithub);
|
||||||
|
$("#item_github_push").click(_pushProjectToGithub);
|
||||||
$("#item_share_file").click(_shareEmbedLink);
|
$("#item_share_file").click(_shareEmbedLink);
|
||||||
$("#item_reset_file").click(_revertFile);
|
$("#item_reset_file").click(_revertFile);
|
||||||
$("#item_rename_file").click(_renameFile);
|
$("#item_rename_file").click(_renameFile);
|
||||||
@ -1455,7 +1490,7 @@ function startPlatform() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadScript(scriptfn, onload, onerror?) {
|
export function loadScript(scriptfn, onload, onerror?) {
|
||||||
var script = document.createElement('script');
|
var script = document.createElement('script');
|
||||||
script.onload = onload;
|
script.onload = onload;
|
||||||
script.onerror = onerror;
|
script.onerror = onerror;
|
||||||
@ -1539,7 +1574,7 @@ export function startUI(loadplatform : boolean) {
|
|||||||
store = createNewPersistentStore(platform_id, (store) => {
|
store = createNewPersistentStore(platform_id, (store) => {
|
||||||
// is this an importURL?
|
// is this an importURL?
|
||||||
if (qs['githubURL']) {
|
if (qs['githubURL']) {
|
||||||
importFromGithub(qs['githubURL']);
|
getGithubService().import(qs['githubURL']);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// is this an importURL?
|
// is this an importURL?
|
||||||
|
69
test/cli/testgithub.js
Normal file
69
test/cli/testgithub.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var vm = require('vm');
|
||||||
|
var fs = require('fs');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
var wtu = require('./workertestutils.js'); // loads localStorage
|
||||||
|
global.localforage = require("localForage/dist/localforage.js");
|
||||||
|
var util = require("gen/util.js");
|
||||||
|
var mstore = require("gen/store.js");
|
||||||
|
var prj = require("gen/project.js");
|
||||||
|
var serv = require("gen/services.js");
|
||||||
|
var Octokat = require('octokat');
|
||||||
|
|
||||||
|
var test_platform_id = "_TEST";
|
||||||
|
|
||||||
|
function newGH(store) {
|
||||||
|
// pzpinfo user
|
||||||
|
return new serv.GithubService(new Octokat({token:'ec64fdd81dedab8b7547388eabef09288e9243a9'}), store);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Store', function() {
|
||||||
|
|
||||||
|
it('Should import from Github', function(done) {
|
||||||
|
var store = mstore.createNewPersistentStore(test_platform_id, function(store) {
|
||||||
|
var gh = newGH(store);
|
||||||
|
gh.import('https://github.com/sehugg/genemedic/extra/garbage').then( (sess) => {
|
||||||
|
assert.equal(4, sess.paths.length);
|
||||||
|
// TODO: test for presence in local storage, make sure returns keys
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should publish (fail) on Github', function(done) {
|
||||||
|
var store = mstore.createNewPersistentStore(test_platform_id, function(store) {
|
||||||
|
var gh = newGH(store);
|
||||||
|
// should fail
|
||||||
|
gh.publish('testrepo4').catch( (e) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should commit/push to Github', function(done) {
|
||||||
|
var store = mstore.createNewPersistentStore(test_platform_id, function(store) {
|
||||||
|
var gh = newGH(store);
|
||||||
|
var files = [
|
||||||
|
{path:'text.txt', data:'hello world'}
|
||||||
|
];
|
||||||
|
gh.commitPush('https://github.com/pzpinfo/testrepo3', 'test commit', files).then( (sess) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should bind paths to Github', function(done) {
|
||||||
|
var store = mstore.createNewPersistentStore(test_platform_id, function(store) {
|
||||||
|
var gh = newGH(store);
|
||||||
|
var sess = {prefix:'prefix', url:'_'};
|
||||||
|
gh.bind(sess, true);
|
||||||
|
assert.equal(gh.getBoundURL('prefix', '_'));
|
||||||
|
gh.bind(sess, false);
|
||||||
|
assert.equal(gh.getBoundURL('prefix', null));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -4,42 +4,7 @@ var vm = require('vm');
|
|||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
|
||||||
var localItems = {};
|
var wtu = require('./workertestutils.js'); // loads localStorage
|
||||||
var localMods = 0;
|
|
||||||
|
|
||||||
global.localStorage = {
|
|
||||||
clear: function() {
|
|
||||||
localItems = {};
|
|
||||||
localMods = 0;
|
|
||||||
this.length = 0;
|
|
||||||
},
|
|
||||||
getItem: function(k) {
|
|
||||||
console.log('get',k);
|
|
||||||
return localItems[k];
|
|
||||||
},
|
|
||||||
setItem: function(k,v) {
|
|
||||||
console.log('set',k,v);
|
|
||||||
if (!localItems[k]) this.length++;
|
|
||||||
localItems[k] = v;
|
|
||||||
localMods++;
|
|
||||||
},
|
|
||||||
removeItem: function(k) {
|
|
||||||
if (localItems[k]) {
|
|
||||||
this.length--;
|
|
||||||
delete localItems[k];
|
|
||||||
localMods++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
length: 0,
|
|
||||||
key: function(i) {
|
|
||||||
var keys = [];
|
|
||||||
for (var k in localItems)
|
|
||||||
keys.push(k);
|
|
||||||
console.log(i,keys[i]);
|
|
||||||
return keys[i];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
global.localforage = require("localForage/dist/localforage.js");
|
global.localforage = require("localForage/dist/localforage.js");
|
||||||
var util = require("gen/util.js");
|
var util = require("gen/util.js");
|
||||||
var mstore = require("gen/store.js");
|
var mstore = require("gen/store.js");
|
||||||
@ -83,7 +48,7 @@ describe('Store', function() {
|
|||||||
project.loadFiles(['local/test','test'], function(err, result) {
|
project.loadFiles(['local/test','test'], function(err, result) {
|
||||||
assert.equal(null, err);
|
assert.equal(null, err);
|
||||||
assert.deepEqual(["presets/_TEST/test"], remote);
|
assert.deepEqual(["presets/_TEST/test"], remote);
|
||||||
assert.deepEqual([ { path: 'local/test', filename: 'test', data: 'a', link:true } ], result);
|
assert.deepEqual([ { path: 'local/test', filename: 'local/test', data: 'a', link:true } ], result);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -69,3 +69,40 @@ includeInThisContext("gen/worker/workermain.js");
|
|||||||
global.ab2str = function(buf) {
|
global.ab2str = function(buf) {
|
||||||
return String.fromCharCode.apply(null, new Uint16Array(buf));
|
return String.fromCharCode.apply(null, new Uint16Array(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global.localItems = {};
|
||||||
|
global.localMods = 0;
|
||||||
|
|
||||||
|
global.localStorage = {
|
||||||
|
clear: function() {
|
||||||
|
localItems = {};
|
||||||
|
localMods = 0;
|
||||||
|
this.length = 0;
|
||||||
|
},
|
||||||
|
getItem: function(k) {
|
||||||
|
console.log('get',k);
|
||||||
|
return localItems[k];
|
||||||
|
},
|
||||||
|
setItem: function(k,v) {
|
||||||
|
console.log('set',k,v.length<100?v:v.length);
|
||||||
|
if (!localItems[k]) this.length++;
|
||||||
|
localItems[k] = v;
|
||||||
|
localMods++;
|
||||||
|
},
|
||||||
|
removeItem: function(k) {
|
||||||
|
if (localItems[k]) {
|
||||||
|
this.length--;
|
||||||
|
delete localItems[k];
|
||||||
|
localMods++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
length: 0,
|
||||||
|
key: function(i) {
|
||||||
|
var keys = [];
|
||||||
|
for (var k in localItems)
|
||||||
|
keys.push(k);
|
||||||
|
console.log(i,keys[i]);
|
||||||
|
return keys[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user