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

Jib Auto Sync - core + maven implementation #3369

Closed
wants to merge 1 commit into from

Conversation

loosebazooka
Copy link
Member

Just putting this up here for now, if it feels like I'm messing too much with the core system maybe we can restructure that. I'll clean up the code some more and add tests if we can kinda agree on the changes in here?

  1. So most of this is baked into the jib package, but I don't think anything in it necessarily HAS to be jib specific. If we want to extend the model out for other systems we can. But it mostly
    feels like a java problem anyway?

  2. Added an InitSync before first build in dev mode to initalize sync of the files - requires a build to get the sync data

  3. I feel like there's some weird cases I haven't handled yet

  4. logging is wrong, probably need to fix that

So most of this is baked into the jib package, but I don't think
anything in it necessarily HAS to be jib specific. If we want to
extend the model out for other systems we can. But it mostly
feels like a java problem anyway?

Gradle is not covered here.
Copy link
Member

@chanseokoh chanseokoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I'm not very familiar with how exactly this works, so there are many questions.

@@ -85,8 +85,24 @@ func getCommandMaven(ctx context.Context, workspace string, a *latest.JibArtifac
return MavenCommand.CreateCommand(ctx, workspace, args)
}

func getSyncMapCommandMaven(ctx context.Context, workspace string, a *latest.JibArtifact) *exec.Cmd {
cmd := MavenCommand.CreateCommand(ctx, workspace, mavenBuildArgs("_skaffold-sync-map", a, true))
Copy link
Member

@chanseokoh chanseokoh Dec 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mavenBuildArgs append either package or prepare-package. Does that make sense? And I don't really think _skaffold-sync-map will work. It should be jib:_skaffold-sync-map?

Also we pass --quiet for _skaffold-files_v2. But I'm not sure if --quiet helps, because I didn't see any Maven output in your short demo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, forget prepending jib:_. I see it's added in mavenBuildArgs.

}

// To parse the output, search for "BEGIN JIB JSON", then unmarshal the next line into the pathMap struct.
matches := regexp.MustCompile(`BEGIN JIB JSON\r?\n({.*})`).FindSubmatch(stdout)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I liked @briandealwis's idea to have this extensible. Something we should keep in mind to make things match.

if (err != nil) {
return err
}
syncLists[artifact.Project] = *syncMap
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that multiple Java projects have the same "JibArtifact.Project" name as a key to the map? The map is a global map, isn't it?

And isn't artifact.Project == "" for a single-module project setup?

Src string `json:"src"`
Dest string `json:"dest"`

filetime time.Time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does an entry always refer to a file and not a directory? Just to understand what the modification time of a directory may mean, if it can be a directory. But I kind of remember that our sync map will list every single file and not directories?

And I always forget. For a Java file, will the entry be a .java file or a .class file?

}
for _, bf := range buildFiles {
if f == bf {
return nil, nil, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the method name, I think it's worth adding a comment nil, nil means a full rebuild.

}

// we need to do another build and get a new sync map
newSyncMap, err := getSyncMap(ctx, workspace, artifact)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so getSyncMap is really supposed to trigger a build itself (i.e., doing package)?

I'd like to understand how this could potentially interfere (race condition) with normal file watching, as we talked about before.

func updateModTime(se []SyncEntry) error {
for i, _ := range se {
e := &se[i]
if info, err := os.Stat(e.Src); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this (and the operation to compute absolute path above) is cheap to do. The sync map will inherently be small, so we should probably good?

@@ -88,6 +88,10 @@ type filesLists struct {
// watchedFiles maps from project name to watched files
var watchedFiles = map[string]filesLists{}

func GetBuildDefinitions(a *latest.JibArtifact) []string {
return watchedFiles[a.Project].BuildDefinitions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect a.Project needs to be combined with the artifact context. As @chanseokoh noted below, a.Project may be the empty string, and it's entirely possible to have two artifacts with different contexts (workspaces) and same project name.


var syncLists = make(map[string]SyncMap)

type SyncMap struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some go doc to describe that this structure is filled in from information from the jib builder (mvn jib:_.../gradle _jib...). I have to admit that Direct didn't have obvious semantics, but I don't have anything better to suggest.

Comment on lines +59 to +60
// returns toCopy, toDelete, error
func GetSyncDiff(ctx context.Context, workspace string, artifact *latest.JibArtifact, e filemon.Events) (map[string][]string, map[string][]string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could consider using named return values to make this more explicit:

func GetSyncDiff(...) (toCopy map[string][]string, toDelete map[string][]string, err error) {

Or maybe it'd be better to return an explicit struct SyncDiff?


if len(e.Deleted) != 0 {
// change into logging
fmt.Println("Deletions are not supported by jib auto sync at the moment")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmt.Println("Deletions are not supported by jib auto sync at the moment")
fmt.Println("Deletions are not yet supported by jib auto sync")

return errors.New("failed to get Jib Sync data")
}

line := bytes.Replace(matches[1], []byte(`\`), []byte(`\\`), -1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line throws me every time I come across it. I believe this replace is required is because of Windows paths? Should we instead fix our emitting code in Jib?



// if all files are modified and direct, we don't need to build anything
if len(e.Deleted) == 0 || len(e.Added) == 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

|| seems at odd with the comment? And we could skip this if len(e.Modified) > len(oldSyncMap.Direct)?

Comment on lines +91 to +97
if !filepath.IsAbs(f) {
if ff, err := filepath.Abs(f); err != nil{
return nil, nil, err
} else {
f = ff
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved to the outer for loop

}

// it seems less than efficient to keep the original JSON structure when doing look ups, so maybe we should only use the json objects for serialization
// and store the sync data in a better type?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original format leads to O(n) checks

if a.Sync != nil && a.Sync.Auto != nil{
if a.JibArtifact != nil {
if err := jib2.InitSync(ctx, a.Workspace, a.JibArtifact); err != nil {
// maybe should just disable sync here, instead of dead?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// maybe should just disable sync here, instead of dead?
// maybe should just disable sync here, instead of dying?

@loosebazooka
Copy link
Member Author

this is covered by a bunch of new PRs

@dgageot dgageot deleted the jib-sync-auto branch May 11, 2020 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants