mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-06 01:20:41 +00:00
feat(git): Implement git clone
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
import path from 'path-browserify';
|
||||
|
||||
export const PROXY_URL = 'https://cors.isomorphic-git.org';
|
||||
|
||||
/**
|
||||
* Attempt to locate the git repository directory.
|
||||
* @throws Error If no git repository could be found, or another error occurred.
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
// Generated by /tools/gen.js
|
||||
import module_add from './add.js'
|
||||
import module_clone from './clone.js'
|
||||
import module_commit from './commit.js'
|
||||
import module_config from './config.js'
|
||||
import module_help from './help.js'
|
||||
@@ -29,6 +30,7 @@ import module_version from './version.js'
|
||||
|
||||
export default {
|
||||
"add": module_add,
|
||||
"clone": module_clone,
|
||||
"commit": module_commit,
|
||||
"config": module_config,
|
||||
"help": module_help,
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter's Git client.
|
||||
*
|
||||
* Puter's Git client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import git from 'isomorphic-git';
|
||||
import http from 'isomorphic-git/http/web';
|
||||
import { PROXY_URL } from '../git-helpers.js';
|
||||
import { SHOW_USAGE } from '../help.js';
|
||||
import path from 'path-browserify';
|
||||
|
||||
export default {
|
||||
name: 'clone',
|
||||
usage: 'git clone <repository> [<directory>]',
|
||||
description: 'Clone a repository into a new directory.',
|
||||
args: {
|
||||
allowPositionals: true,
|
||||
options: {
|
||||
depth: {
|
||||
description: 'Only clone the specified number of commits. Implies --single-branch unless --no-single-branch is given.',
|
||||
type: 'string',
|
||||
},
|
||||
'single-branch': {
|
||||
description: 'Only clone the history of the primary branch',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
'no-single-branch': {
|
||||
description: 'Clone all history (default)',
|
||||
type: 'boolean',
|
||||
},
|
||||
'no-tags': {
|
||||
description: 'Do not clone any tags from the remote',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
execute: async (ctx) => {
|
||||
const { io, fs, env, args } = ctx;
|
||||
const { stdout, stderr } = io;
|
||||
const { options, positionals } = args;
|
||||
|
||||
if (options.depth) {
|
||||
const depth = Number.parseInt(options.depth);
|
||||
if (!depth) {
|
||||
stderr('Invalid --depth: Must be an integer greater than 0.');
|
||||
return 1;
|
||||
}
|
||||
options.depth = depth;
|
||||
options['single-branch'] = true;
|
||||
}
|
||||
|
||||
if (options['no-single-branch']) {
|
||||
options['single-branch'] = false;
|
||||
delete options['no-single-branch'];
|
||||
}
|
||||
|
||||
const [repository, directory] = positionals;
|
||||
if (!repository) {
|
||||
stderr('fatal: You must specify a repository to clone.');
|
||||
throw SHOW_USAGE;
|
||||
}
|
||||
|
||||
let repo_path;
|
||||
if (directory) {
|
||||
repo_path = path.resolve(env.PWD, directory);
|
||||
} else {
|
||||
// Try to extract directory from the repository url
|
||||
let repo_name = repository.slice(repository.lastIndexOf('/') + 1);
|
||||
if (repo_name.endsWith('.git')) {
|
||||
repo_name = repo_name.slice(0, -4);
|
||||
}
|
||||
|
||||
repo_path = path.resolve(env.PWD, repo_name);
|
||||
}
|
||||
|
||||
// The path must either not exist, or be a directory that is empty
|
||||
try {
|
||||
const readdir = await fs.promises.readdir(repo_path);
|
||||
if (readdir.length !== 0) {
|
||||
stderr(`fatal: ${repo_path} is not empty.`);
|
||||
return 1;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT') {
|
||||
stderr(`fatal: ${repo_path} is a file.`);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
stdout(`Cloning into '${path.relative(env.PWD, repo_path)}'...`);
|
||||
|
||||
await git.clone({
|
||||
fs,
|
||||
http,
|
||||
corsProxy: PROXY_URL,
|
||||
dir: repo_path,
|
||||
url: repository,
|
||||
depth: options.depth,
|
||||
singleBranch: options['single-branch'],
|
||||
noTags: options['no-tags'],
|
||||
onMessage: (message) => { stdout(message); },
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user