Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Use LibGit2Sharp instead of installing whole Git #4881

Open
couleurm opened this issue Apr 18, 2022 · 19 comments
Open

[Feature] Use LibGit2Sharp instead of installing whole Git #4881

couleurm opened this issue Apr 18, 2022 · 19 comments

Comments

@couleurm
Copy link

Feature Request

Is your feature request related to a problem? Please describe.

Scoop looses a bit of it's magic if you don't install git (buckets, updates, etc..)

Describe the solution you'd like

Why not use LibGit2Sharp? It lets you clone repositories with PowerShell while it's only a few hundred kilobytes. I'm not sure about if it can pull / show new commits but I doubt it'd need to be that bigger. Because of it's small size it could come with the scoop installer and let people easily add other buckets

Describe alternatives you've considered

None other I can think of

@rashil2000
Copy link
Member

It's a nice idea, but can the library show git logs and style them like we do currently?

@niheaven
Copy link
Member

Marked and MAY adopt this idea, thanks!

@rasa
Copy link
Member

rasa commented Apr 19, 2022

Removing the dependency of 7zip would be nice too, but https://github.com/thoemmi/7Zip4Powershell uses 7z.dll, and I recall that 7z.dll doesn't have all the functionality we need of 7zip.exe. I think it was that expanding .exe's required 7z.exe, but I'm not sure.

@r15ch13
Copy link
Member

r15ch13 commented Apr 19, 2022

Well, I actually tried that before 😁
https://github.com/ScoopInstaller/GitCloner/blob/master/src/gitcloner.ps1

It seems to support git log.
https://github.com/libgit2/libgit2sharp/wiki/git-log
https://github.com/libgit2/libgit2sharp/wiki/git-log-name-status

@couleurm
Copy link
Author

Well, I actually tried that before 😁 https://github.com/ScoopInstaller/GitCloner/blob/master/src/gitcloner.ps1

It seems to support git log. https://github.com/libgit2/libgit2sharp/wiki/git-log https://github.com/libgit2/libgit2sharp/wiki/git-log-name-status

Did you encounter any issues that stopped you from implementing git-cloner to scoop?

@r15ch13
Copy link
Member

r15ch13 commented Apr 20, 2022

Probably the log issue. Don't know anymore 😄
Currently trying to implement the logging. (Failing to get the x minutes/hours ago part with the correct values)

@couleurm
Copy link
Author

couleurm commented Apr 20, 2022

Currently trying to implement the logging

I'll keep an eye on ScoopInstaller/GitCloner thank you 👀👀

@r15ch13
Copy link
Member

r15ch13 commented Apr 20, 2022

So this is what I came up with. But there might be a license problem, because I based the ConvertTo-RelativeDate-Function on the show_date_relative() from Git itself. (I don't know if the GPL-2.0 allows us to do that. 🤷🏽‍♂️)

The output is the same as git --no-pager log --no-decorate --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' '$previousCommit..HEAD'.
Some commits get switched if they are commited at the exact same second. (not a problem)

<#
.SYNOPSIS
    Shows the git log from a past commit hash to HEAD
.DESCRIPTION
    A small script shows the git log from a given commit hash to the current HEAD
.PARAMETER Repository
    Valid path to local Git repository
.PARAMETER StartHash
    The commit hash uses to create the log '$hash..HEAD'
.PARAMETER Color
    Switch for colored output
.EXAMPLE
    PS > .\gitlogger.ps1 -Repository '~/scoop/bucket/main' -StartHash "2d09f7c00" -Color
#>
param (
    [Parameter(Mandatory = $true, Position = 0)]
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Repository,
    [Parameter(Mandatory = $true, Position = 1)]
    [String] $StartHash = "",
    [Switch] $Color
)

Add-Type -TypeDefinition @"
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    public static class Kernel32
    {
        [DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
        public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
    }
"@


if([System.IntPtr]::Size -eq 8) {
    [Kernel32]::LoadLibrary((Get-ChildItem "$PSScriptRoot\lib\win32\x64\git2-???????.dll" | Select-Object -First 1).FullName) | Out-Null
} else {
    [Kernel32]::LoadLibrary((Get-ChildItem "$PSScriptRoot\lib\win32\x86\git2-???????.dll" | Select-Object -First 1).FullName) | Out-Null
}

Add-Type -Path "$PSScriptRoot\LibGit2Sharp.dll"

function ConvertTo-PluralizedString {
    [OutputType([String])]
    param (
        [Parameter(Mandatory = $true)]
        [Int]
        $Value,
        [Parameter(Mandatory = $true)]
        [String]
        $Singular,
        [Parameter(Mandatory = $true)]
        [String]
        $Plural
    )
    if($Value -gt 1) {
        return $Plural -f $Value
    }
    return $Singular -f $Value
}

# Based on https://github.com/git/git/blob/master/date.c
function ConvertTo-RelativeDate {
    [OutputType([String])]
    param (
        [Parameter(Mandatory = $true, Position = 1)]
        [DateTimeOffset]
        $Date
    )

    $ts = New-TimeSpan -Start $Date.LocalDateTime.Ticks
    $diff = $ts.TotalSeconds

    if($diff -lt 0) {
        return "in the future"
    }

    # Turn it into minutes
    $diff = ($diff + 30) / 60;
    if($diff -lt 90) {
        return ConvertTo-PluralizedString -Singular "{0} minute ago" -Plural "{0} minutes ago" -Value ([int][Math]::Floor($diff))
    }

    # Turn it into hours
    $diff = ($diff + 30) / 60;
    if ($diff -lt 36) {
        return ConvertTo-PluralizedString -Singular "{0} hour ago" -Plural "{0} hours ago" -Value ([int][Math]::Floor($diff))
    }

    # We deal with number of days from here on
    $diff = ($diff + 12) / 24;
    if ($diff -lt 14) {
        return ConvertTo-PluralizedString -Singular "{0} day ago" -Plural "{0} days ago" -Value ([int][Math]::Floor($diff))
    }

    # Say weeks for the past 10 weeks or so
    if ($diff -lt 70) {
        return ConvertTo-PluralizedString -Singular "{0} week ago" -Plural "{0} weeks ago" -Value ([int][Math]::Floor(($diff + 3) / 7))
    }

    # Say months for the past 12 months or so
    if ($diff -lt 365) {
        return ConvertTo-PluralizedString -Singular "{0} month ago" -Plural "{0} months ago" -Value ([int][Math]::Floor(($diff + 15) / 30))
    }

    # Give years and months for 5 years or so
    if ($diff -lt 1825) {
        $totalmonths = ([int][Math]::Floor($diff) * 12 * 2 + 365) / (365 * 2);
        $years = [int][Math]::Floor($totalmonths / 12);
        $months = [int][Math]::Floor($totalmonths % 12);
        if ($months) {
            $sb = ConvertTo-PluralizedString -Singular "{0} year" -Plural "{0} years" -Value $years
            # TRANSLATORS: "%s" is "<n> years"
            return ConvertTo-PluralizedString -Singular "$sb, {0} month ago" -Plural "$sb, {0} months ago" -Value $months
        } else {
            return ConvertTo-PluralizedString -Singular "{0} year ago" -Plural "{0} years ago" -Value $years
        }
    }

    # Otherwise, just years. Centuries is probably overkill.
    return ConvertTo-PluralizedString -Singular "{0} year ago" -Plural "{0} years ago" -Value ([int][Math]::Floor(($diff + 183) / 365))
}

$repo = New-Object -TypeName LibGit2Sharp.Repository -ArgumentList $Repository
$properties = @{
    IncludeReachableFrom = 'HEAD';
}
if($StartHash.Length -gt 0) {
    $properties.ExcludeReachableFrom = $StartHash
}
$filter = New-Object -TypeName LibGit2Sharp.CommitFilter -Property $properties

# Recreates the following 'git log' command
# git --no-pager log --no-decorate --format='tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s %C(cyan)%cr%Creset' '$previousCommit..HEAD'
try {
    if(!$Color) {
        $repo.Commits.QueryBy($filter) | ForEach-Object {
            $msg = $_.MessageShort.Trim().PadRight(59)
            if($msg.Length -gt 59) {
                $msg = "{0}.." -f $msg.Substring(0, 57)
            }
            $row = " * {0} {1} {2}" -f $_.Sha.Substring(0, 9), $msg, (ConvertTo-RelativeDate -Date $_.Author.When)
            Write-Output $row
        }
    } else {
        $repo.Commits.QueryBy($filter) | ForEach-Object {
            $msg = $_.MessageShort.Trim().PadRight(59)
            if($msg.Length -gt 59) {
                $msg = "{0}.." -f $msg.Substring(0, 57)
            }
            Write-Host -NoNewline " * "
            Write-Host -NoNewline -ForegroundColor DarkYellow $_.Sha.Substring(0, 9)
            Write-Host -NoNewline " $msg "
            Write-Host -ForegroundColor DarkCyan (ConvertTo-RelativeDate -Date $_.Author.When)
        }
    }
} catch [Exception] {
    Write-Output $_.Exception.Message
}

@couleurm
Copy link
Author

couleurm commented May 4, 2022

Using LibGit2Sharp would greatly accelerate installation speed, unzipping the main bucket is soo long..

@miniyou
Copy link

miniyou commented Jun 21, 2022

I like the overall idea. Just a word of warning: LibGit2Sharp has been lacking a maintainer for a couple of years. That doesn't need to be a blocker, but you should weigh it into the overall effort of implementing this issue, since you may have to maintain your own fork.

@couleurm
Copy link
Author

couleurm commented Oct 20, 2022

Would be also cool if we used a DLL for 7-Zip (7z.dll) (if possible), since there's already DLLs in Scoop

@niheaven
Copy link
Member

Will be, maybe in a 'plugins' feature.

@r15ch13
Copy link
Member

r15ch13 commented Feb 18, 2023

Another possible solution: Reducing MinGit to just git.exe , git-remote-https.exe, *.dll, license, ca-certs, and hook templates.
Results in a ~8 MB ZIP or ~16 MB on disk.

image

@couleurm
Copy link
Author

yeah i dont think mingw is needed

though having this means as git in PATH could conflict with a real git..?

@r15ch13
Copy link
Member

r15ch13 commented Feb 18, 2023

What you see above is without mingw, but the DLLs are required to run git.exe. I just copied the DLLs over bit by bit until git.exe started working (in Windows Sandbox) 😄
This version of git would only be used internally without exposing it to the user environment.

@couleurm
Copy link
Author

couleurm commented Feb 19, 2023

great! that should help cut down the installation setup time 👍👍 (i mean git isn't installed right at setup but still is a core part of scoop)

@rashil2000
Copy link
Member

great! that should help cut down the installation setup time 👍👍

That should be fixed now btw, because of ScoopInstaller/Install#42

@i2
Copy link

i2 commented Jun 1, 2023

git for scoop is around 350MB (mingw64 being 150MB of it). Has there been any outcome out of this libgit2 effort lately?

@goyalyashpal
Copy link

goyalyashpal commented Apr 12, 2024

copying over from duplicate discussion.

  • i created this discussion as i was not actively aware of any small implementations of git for windows,
  • but here there are many.
  • so, switching to fossil would be more of a hack if there are not much additional benefits to it.
  • but i don't know, as i have never used that; and never dived beneath the surface of git either.

continuing from here: #5885

so, on the client's win 7 system, using extras/doublecmd application, i navigated to the scoop-apps directory, and the git-portable or whatever was at the top consuming whopping 3xx MB of space.

this is whopping due to following reasons:

  • as that system is old and constrained on disk space.
  • for non-tech people who do not use git, this is way too much of a consumption by a needless superfluous application

so, i'd like to explore using main/fossil vcs for pulling the git buckets. it was only 30-40 MB the last time i used that.
and it says that it can work with git. but i don't know if it can work with remote-gits too...

upside:

  • uses sqlite db to store git info, so, the database might very well be used directly lol

downside:

  • would still need to extract/use only dlls etc,
  • since fossil has lots of other stuff (like issue tracker, wiki, browser GUI, etc) beside just the "git-like" part.

versions

$ scoop --version | head -n2
Current Scoop version:
v0.3.1 - Released at 2022-11-15

$ scoop info fossil


Name        : fossil
Description : A simple, high-reliability, distributed software configuration management system.
Version     : 2.23
Bucket      : main
Website     : https://www.fossil-scm.org
License     : BSD-2-Clause
Updated at  : 2023-11-02 01:54:26
Updated by  : github-actions[bot]
Binaries    : fossil.exe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants