Re: [PATCH] Replace HTTP links with HTTPS ones: Documentation/translations/it_IT
From: Alexander A. Klimov
Date: Thu Jun 11 2020 - 07:02:34 EST
Am 11.06.20 um 12:40 schrieb Miguel Ojeda:
On Thu, Jun 11, 2020 at 9:02 AM Alexander A. Klimov
<grandmaster@xxxxxxxxxxxx> wrote:
Is any of you familiar with Golang?
Don't worry about that! I'd expect seasoned C programmers to be able
to read Go (or near languages) -- at least to have a general idea of
what an algorithm does.
It is not APL, after all :-)
Fine.
package main
import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
fatomic "github.com/natefinch/atomic"
"golang.org/x/sync/semaphore"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"regexp"
"runtime"
"sync"
"sync/atomic"
"time"
)
var fileSemaphore = semaphore.NewWeighted(int64(runtime.NumCPU()) * 16)
var wg sync.WaitGroup
var processingFiles = struct {
sync.RWMutex
files map[string]struct{}
}{
files: map[string]struct{}{},
}
func main() {
cmd := exec.Command("git", "ls-files", "-sz")
cmd.Stderr = os.Stderr
out, errSP := cmd.StdoutPipe()
if errSP != nil {
fmt.Fprintln(os.Stderr, errSP.Error())
os.Exit(1)
}
if errSt := cmd.Start(); errSt != nil {
fmt.Fprintln(os.Stderr, errSt.Error())
os.Exit(1)
}
//go printProcessingFiles()
buf := bufio.NewReader(out)
for {
file, errRB := buf.ReadBytes(0)
if errRB != nil && errRB != io.EOF {
if errWt := cmd.Wait(); errWt != nil {
fmt.Fprintln(os.Stderr, errWt.Error())
wg.Wait()
os.Exit(1)
}
fmt.Fprintln(os.Stderr, errRB.Error())
wg.Wait()
os.Exit(1)
}
if bytes.HasPrefix(file, []byte{'1', '0', '0'}) {
if fields := bytes.SplitN(bytes.SplitN(file, []byte{0}, 2)[0],
[]byte{9}, 2); len(fields) == 2 {
_ = fileSemaphore.Acquire(context.Background(), 1)
wg.Add(1)
go processFile(string(fields[1]))
}
}
if errRB == io.EOF {
break
}
}
wg.Wait()
if errWt := cmd.Wait(); errWt != nil {
fmt.Fprintln(os.Stderr, errWt.Error())
os.Exit(1)
}
}
/*
func printProcessingFiles() {
for {
time.Sleep(time.Second)
processingFiles.RLock()
fmt.Fprintln(os.Stderr, processingFiles.files)
processingFiles.RUnlock()
}
}
*/
var httpLink = regexp.MustCompile(`\bhttp://[^# \t\r\n]*(?:\w|/)`)
var xmlns = regexp.MustCompile(`\bxmlns\b`)
func processFile(file string) error {
defer fileSemaphore.Release(1)
defer wg.Done()
processingFiles.Lock()
processingFiles.files[file] = struct{}{}
processingFiles.Unlock()
defer func() {
processingFiles.Lock()
delete(processingFiles.files, file)
processingFiles.Unlock()
}()
content, errRF := ioutil.ReadFile(file)
if errRF != nil {
return errRF
}
lines := bytes.Split(content, []byte{'\n'})
for i := range lines {
if !xmlns.Match(lines[i]) {
lines[i] = httpLink.ReplaceAllFunc(lines[i], processLink)
}
}
if modified := bytes.Join(lines, []byte{'\n'}); bytes.Compare(modified,
content) != 0 {
var buf bytes.Buffer
buf.Write(modified)
return fatomic.WriteFile(file, &buf)
}
return nil
}
type linkOk struct {
sync.Mutex
ok uint32
}
var links = map[string]*linkOk{}
var linksLock sync.RWMutex
var notsecure = http.Client{Timeout: 10 * time.Minute}
var secure = http.Client{Timeout: 10 * time.Minute, CheckRedirect:
httpsRedirect}
func processLink(link []byte) []byte {
linkStr := string(bytes.TrimPrefix(link, []byte("http://")))
linksLock.RLock()
lo, ok := links[linkStr]
linksLock.RUnlock()
if !ok {
linksLock.Lock()
lo, ok = links[linkStr]
if !ok {
lo = &linkOk{}
links[linkStr] = lo
}
linksLock.Unlock()
}
for {
switch atomic.LoadUint32(&lo.ok) {
case 0:
lo.Lock()
if atomic.LoadUint32(&lo.ok) == 0 {
if httpsAble(linkStr) {
atomic.StoreUint32(&lo.ok, 2)
} else {
atomic.StoreUint32(&lo.ok, 1)
}
}
lo.Unlock()
continue
case 2:
return bytes.Replace(link, []byte("http://"), []byte("https://"), 1)
default:
return link
}
}
}
func httpsAble(link string) bool {
resp, errGt := secure.Get("https://" + link)
if errGt != nil {
return false
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return false
}
resps, errGt := notsecure.Get("http://" + link)
if errGt != nil {
return false
}
defer resps.Body.Close()
if resps.StatusCode != 200 {
return false
}
var buf, bufs bytes.Buffer
if _, errCp := io.Copy(&buf, resp.Body); errCp != nil {
return false
}
if _, errCp := io.Copy(&bufs, resps.Body); errCp != nil {
return false
}
return bytes.Compare(buf.Bytes(), bufs.Bytes()) == 0
}
var insecure = errors.New("insecure")
func httpsRedirect(req *http.Request, _ []*http.Request) error {
switch req.URL.Scheme {
case "", "https":
return nil
}
return insecure
}
@Maintainers Would any of you actually review like this? If yes, is the
pseudo-code not enough?
Well, Kees already mentioned he would like to see it :-) As he said,
it is usually the way for bulk patches to present the
algorithm/semantic patch/etc. that was used.
It is also useful to have it around so that it can be reused/reapplied
later on, too.
If you're going to reproduce one of my patches for reviewing, checkout
torvalds/master and travel back to the latest commit before I submitted
the patch. Then run the algo.
I didn't log that link-by-link. Maybe because I also didn't follow plain
HTTP redirects while opening HTTPS links. Maybe it even matched, but was
added after I made the changes.
It would be nice to have a list of links which cannot be converted,
since nowadays they are likely to be the exception rather than the
rule.
Don't worry, (by typing this words right now) I've noted this TODO of
mine (after this patch round).
* Linus *didn't even respond* (at least I didn't receive anything) to my
catch-them-all patch at all, not even like please not as .gz attachment
or please split by subsystem
Please take into account that LKML volume is huge and Linus (like
everybody else) only reads a small subset. Further, as a general rule,
I've addressed Linus directly (CC LKML) and explicitly asked like will
you have a look at this or not.
Linus shouldn't be picking individual patches to begin with because
that skips the review tree.
Who if not Linus shall review one huge patch spreading across lots of
subsystems?
Cheers,
Miguel