feat(git): Implement git clone

This commit is contained in:
Sam Atkins
2024-05-31 17:49:19 +01:00
committed by Eric Dubé
parent fa81dca950
commit 95c8235a4a
3 changed files with 123 additions and 0 deletions
+2
View File
@@ -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,
+119
View File
@@ -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); },
});
}
}